views:

161

answers:

3

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

+2  A: 

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.

Robert Christie
+1 and you can include the timing limit in the while loop statement via System.currentMillis or so
Karussell
+5  A: 

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.

Stephen C
I would prefer isInterrupted() since it does not rely on the interruption flag like interrupted()
Karussell
@Karussell - for the record, both isInterrupted() and interrupted() "rely on" the interruption flag. The difference is that isInterrupted() does not reset the flag.
Stephen C
I've edited my post with the problems interrupting. Hopefully it's clearer now or maybe I've missed something? Thanks to everyone who has responded so far though, one solution I'm certain would work (but take longer to change the code). The other (interrupting) I'm probably just missing something/being dense.
Thomas King
@Stephen that was that what I meant. So using interrupted() is a bit 'dangerous'
Karussell
A: 

You do that by implementing a Runnable

public void run()
{
  long time = System.nanoTime(),
       end  = time + 5 000 000 000; // just better formatting
  do {
    ...my code

  } while (System.nanoTime() < end && myOwnCondition);
}
  • Interrupt is not such a good solution, because you need to access the thread from outside and it disturbs the program flow. The thread can terminate anytime in your code which makes cleanup difficult. Please form a habit of letting threads run to the end because otherwise it opens nasty and difficult bugs.

  • If your program is so heavy duty that you don't know that the while end is reached until the task has completed I suggest the use of a labeled break:

    do {
      breakout:
      {
        ..my code
        if (timetest)
          break breakout;      
      }
      // cleanup
      ...
    } while (...);
    
Thorsten S.
Not responding to an interrupted exception is the biggest mistake you can make in concurrent programming. You will notice so many of the j.u.c classes throw and handle interrupted exceptions. In real world programming not only is interrupted exception a good solution its usually the best solution. If someone handles interruption correctly then there wouldnt be those bugs you are suggesting
John V.