Stopping a loop in Java

I use a stream that is continuously read from the 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() deprecated, I can implement the stopThisThread() method, which uses the n atomic check variable.

2 - Send a death event object or something similar to the queue. When a thread receives a death event, it exits.

I prefer the 1st method, however, I do not know when to call the stopThisThread() method, because something may be on the way to the queue, and the stop signal may arrive first (undesirable).

Any suggestions?

+6
java multithreading
source share
6 answers

DeathEvent (or, as it is often called, a "poison pill") works well if you need to complete all the work in the queue before closing. The problem is that this can take a long time.

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

 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 created with this run method, just call t.interrupt(); .

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

I also argue that an additional stop flag is not needed, and in the big picture it is potentially dangerous. The correct working thread must respect interruption. An unexpected interruption simply means that the worker starts in a context that the original programmer did not expect. Best of all, if the employee does what they are told ... that is, he must stop ... regardless of whether this corresponds to the original concept of the programmer.

+6
source share

There is a stop with a boolean value in your read stream. If you want this thread to stop setting thius to true and interrupt the thread. Within the reader thread, when it is safe (when you do not have an unprocessed object), check the state of the stop variable and return from the loop if it is set. as shown below.

 public class readerThread extends Thread{ private volitile boolean stop = false; public void stopSoon(){ stop = true; this.interrupt(); } public void run() { Object obj; while(true) { if(stop){ return; } synchronized(objectsQueue) { if(objectesQueue.isEmpty()) { try { objectesQueue.wait(); } catch (InterruptedException e) { e.printStackTrace(); } if(stop){ return; } obj = objectesQueue.poll(); // Do something with the Object obj } } } } public class OtherClass{ ThreadReader reader; private void start(){ reader = ...; reader.start(); } private void stop(){ reader.stopSoon(); reader.join(); // Wait for thread to stop if nessasery. } } 
+1
source share

Why not use a scheduler that you can simply stop if necessary? The standard scheduler supports re-scheduling, which also waits for the workflow to complete before reconfiguring a new run.

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

this sample will start your thread with a delay of 10 seconds, which means that when one start is completed, it restarts it after 10 seconds. And instead of reinventing the wheel, you get

 service.shutdown() 

while (true) is no longer required.

ScheduledExecutorService Javadoc

+1
source share

Approach 1 is preferred.

Just set the volatile stop field to true and call interrupt() on the current thread. This will force any I / O methods that are waiting to return using InterruptedException (and if your library is written correctly, it will be handled gracefully).

0
source share

I think your two cases actually exhibit the same potential behavior. In the second case, consider Thread A by adding DeathEvent, after which Thread B adds FooEvent. When your Thread task receives a DeathEvent, it still has FooEvent behind it, which is the same scenario that you describe in Option 1, unless you try to clear the queue before returning, but then you essentially keep the thread alive when that you are trying to stop it.

I agree with you that the first option is more desirable. A potential solution will depend on how your line is filled. If this is part of your workflow, you can force your stopThisThread () method to set a flag that returns the appropriate value (or exception exception) from the ie calling call:

 MyThread extends Thread{ boolean running = true; public void run(){ while(running){ try{ //process queue... }catch(InterruptedExcpetion e){ ... } } } public void stopThisThread(){ running = false; interrupt(); } public boolean enqueue(Object o){ if(!running){ return false; OR throw new ThreadNotRunningException(); } queue.add(o); return true; } } 

Then the responsibility for the object will be attempted to be inserted into the Event in order to deal with it accordingly, but at least it will know that the event is not in the queue and will not be processed.

0
source share

I usually put a flag in a class that has a thread in it, and in my code I would do the code. (NOTE: Instead of while (true), I do while (flag))

Then create a method in the class to set the flag to false:

 private volatile bool flag = true; public void stopThread() { flag = false; } public void run() { Object obj; while(flag) { synchronized(objectsQueue) { if(objectesQueue.isEmpty()) { try { objectesQueue.wait(); } catch (InterruptedException e) { e.printStackTrace(); } obj = objectesQueue.poll(); } } // Do something with the Object obj } } 
0
source share

All Articles