Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java: Stopping a thread that has run for too long?

Say I've got something like this

public void run(){
    Thread behaviourThread = new Thread(abstractBehaviours[i]);
    behaviourThread.start();
}

And I want to wait until abstractBehaviours[i] run method has either finished or run for 5000 milliseconds. How do I do that? behaviourThread.join(5000) doesn't seem to do that afaik (something is wrong with my code and I've put it down to that).

All the abstract abstractBehaviour class is of course Runnable. I don't want to implement it inside each run method as that seems ugly and there are many different behaviours, I'd much rather have it in the calling/executing thread and do it just once.

Solutions? First time doing something as threaded as this. Thanks!

edit: So the interrupting solution would be ideal (requiring minimal changes to AbstractBehaviour implementations). BUT I need the thread to stop if it has finished OR 5000 milliseconds have passed so something like the following would not work because the thread may finish before the while loop in the parent thread has. Make sense? Any ways around this, I'd love to do it from within the thread that starts the threads obviously.

long startTime = System.currentTimeMillis();
behaviourThread.start();
while(!System.currentTimeMilis - startTime < 5000);
behaviourThread.interrupt();
try {
    behaviourThread.join();
} catch (InterruptedException e1) {
    e1.printStackTrace();
}

edit: nevermind I see there is a Thread.isAlive() method, all solved I think

like image 284
Dr. Thomas C. King Avatar asked Dec 28 '22 22:12

Dr. Thomas C. King


2 Answers

The best way to do this is to use the thread interrupt mechanism. The worker thread / Runnable needs to periodically call Thread.interrupted() to see if it is time to stop. The second part of the equation is that a separate thread needs to call Thread.interrupt() on the worker thread after 5000 milliseconds have elapsed.

The advantages of using thread interrupts (over a bespoke solution using flags) include:

  • The interrupted() state is always available for the current thread. You don't need to pass around an object handle or use a singleton.
  • An interrupt will unblock some blocking IO and synchronization requests. A bespoke solution cannot do this.
  • Third-party Java applications and libraries may respect Thread.interrupt().

EDIT - as a commenter points out, you can test whether the current thread has been interrupted using either Thread.interrupted() or Thread.currentThread().isInterrupted(). The main difference between the two approaches is that the former clears the interrupted flag, but the latter doesn't.

like image 150
Stephen C Avatar answered Dec 31 '22 13:12

Stephen C


You cannot do this externally from the run method - the run method must check some variable to see if it should exit. For example:

class InterruptableRunnable implements Runnable
{
   private volatile boolean stop;
   public setStop() {
       stop = true;
   }

   public void run() {
        while (!stop)
        {
            //do some work and occassionaly fall through to check that stop is still true
        }
   }
}

The key thing is for the code in the run loop to check the stop flag occasionally. You can then wire up a timer to set stop to true after 5000 milliseconds.

Finally, it's best practice not to use Threads directly, use the excellent Concurrency Framework. The Concurrency Tutorial is a good place to start and the book Java Concurrency in practice is excellent.

like image 24
Robert Christie Avatar answered Dec 31 '22 13:12

Robert Christie