Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stopping looping thread in Java

I'm using a thread that is continuously reading from a queue.

Something like:

public void run() {
    Object obj;
    while(true) {
        synchronized(objectsQueue) {
            if(objectesQueue.isEmpty()) {
                try {
                    objectesQueue.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                obj = objectesQueue.poll();
            }
        }

        // Do something with the Object obj
    }
}

What is the best way to stop this thread?

I see two options:

1 - Since Thread.stop() is deprecated, I can implement a stopThisThread() method that uses a n atomic check-condition variable.

2 - Send a Death Event object or something like that to the queue. When the thread fetches a death event, it exits.

I prefer the 1st way, however, I don't know when to call the stopThisThread() method, as something might be on it's way to the queue and the stop signal can arrive first (not desirable).

Any suggestions?

like image 906
halfwarp Avatar asked Apr 27 '10 11:04

halfwarp


2 Answers

The DeathEvent (or as it is often call, "poison pill") approach works well if you need to complete all of the work on the queue before shutting down. The problem is that this could take a long time.

If you want to stop as soon as possible, I suggest you do this

BlockingQueue<O> queue = ...

...

public void run() {
   try {
       // The following test is necessary to get fast interrupts.  If
       // it is replaced with 'true', the queue will be drained before
       // the interrupt is noticed.  (Thanks Tim)
       while (!Thread.interrupted()) {
           O obj = queue.take();
           doSomething(obj);
       }
   } catch (InterruptedException ex) {
       // We are done.
   }
}

To stop the thread t that instantiated with that run method, simply call t.interrupt();.

If you compare the code above with other answers, you will notice how using a BlockingQueue and Thread.interrupt() simplifies the solution.

I would also claim that an extra stop flag is unnecessary, and in the big picture, potentially harmful. A well-behaved worker thread should respect an interrupt. An unexpected interrupt simply means that the worker is being run in a context that the original programmer did not anticipate. The best thing is if the worker to does what it is told to do ... i.e. it should stop ... whether or not this fits with the original programmer's conception.

like image 160
Stephen C Avatar answered Sep 21 '22 11:09

Stephen C


Why not use a scheduler which you simply can stop when required? The standard scheduler supports repeated scheduling which also waits for the worker thread to finish before rescheduling a new run.

ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
service.scheduleWithFixedDelay(myThread, 1, 10, TimeUnit.SECONDS);

this sample would run your thread with a delay of 10 sec, that means when one run finishes, it restarts it 10 seconds later. And instead of having to reinvent the wheel you get

service.shutdown()

the while(true) is not necessary anymore.

ScheduledExecutorService Javadoc

like image 37
dube Avatar answered Sep 25 '22 11:09

dube