Question

I know the construct of terminating a thread gracefully:

public class Foo implements Runnable {
   private volatile boolean stop = false;

   public void stop() {
      stop = true;
   }

   public void run() {
      while (!stop) {
         ...
      }
   }
}

But if some thread is waiting for something, inside some object (using wait(), without time limit), then this construct won't be useful to stopping this thread, because he is already past the condition in the while loop, so he will continue forever.

So, what is the right way to stop the waiting threads?

Was it helpful?

Solution

If the Thread is actually waiting for something, you should call the method Thread.interrupt() to interrupt the thread. Instead of checking for your custom variable in the while loop, use Thread.isInterrupted() or Thread.interrupted() - one resets the interruption flag, the other doesn't.

If you are waiting on something, I assumed you had to catch the InterruptedException, didn't you?

OTHER TIPS

If you don't want your threads to wait indefinitely, don't code them to do that in the first place. You're writing their code, so write it to do what you actually so you don't have to try to fix it from the outside.

Every well-behaved blocking method declares a the checked exception InterruptedException, which serves this exact purpose: to notify that the thread has been interrupted while it was blocked.

You have to catch this exception, and actually this could replace your stop field.

For instance, let's consider a logging system that will write messages to a file on a dedicated thread (so that the time spent on IO will not interfere in your application -- assuming it is not IO heavy).

Every thread has an initerrupted flag that can be read through Thread.currentThread().isInterrupted(). You try something like this:

class Logger {
  private final File file = ...;
  private final BlockingQueue<String> logLines = new LinkedBlockingQueue<String>();
  private final Thread loggingThread = new Thread(new Runnable(){
    @Override public void run() {
      PrintWriter pw;
      try {
        pw = new PrintWriter(new BufferedOutputStream(new FileOutputStream(file)));
        while (!Thread.currentThread().isInterrupted()) {
          try {
            pw.println(logLines.take());
          } catch (InterruptedException e) {
            Thread.currentThread().interrupt(); // good habit: make sure the interrupt status is set
          }
        }
        pw.flush();
        pw.close();
      } catch (IOException e) { ... flush and close pw if not null and open ... }
    }
  });
  { loggingThread.start(); }
  public void log(final String line) { logLines.offer(line); } // will always work, because logLines is a LinkedBQ.
  public void stop() { loggingThread.interrupt(); }
}

Finally, for a graceful shutdown of your application, you must be sure to terminate this thread before letting the JVM shutdown. To do so, you must either be absolutely certain to call stop() before shutting down in any possible way, or you could register a shutdown hook, by adding something like this instance initializer to the class:

class Logger {
  ...
  {
    Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
      @Override public void run() { close(); }
    }));
  }
}

This will force the JVM to call close() (therefore interrupting the thread, flushing and closing the file) before terminating.

That all depends on why you have to wait in your thread. If the thread is waiting on an uninterruptible IO, then you can take a look at Stop/Interrupt threads blocked on waiting input from socket

Otherwise it all depends on how you wait in the thread. You could use wait(1000), then check for the flag and wait some more. You could wait for a message from a blocking queue, you could use locks/conditions, even wait/notify could work in this case you would need to handle interrupts properly.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top