9

I want to set timeouts for threads which are executed within a thread pool. At the moment I have following code:

ExecutorService executor = Executors.newFixedThreadPool(8);
for(List<String> l: partition) {            
    Runnable worker = new WorkerThread(l);
    executor.execute(worker);
}       

executor.shutdown();
while (!executor.isTerminated()) {

}

The code just splits a big list of objects into sublists and process these sublist within single threads. But this is not the point.

I want to give each single thread in the thread pool a timeout. For only one thread in the pool I found following solution:

Future<?> future = null;

for (List<String> l : partition) {
    Runnable worker = new WorkerThread(l);
    future = executor.submit(worker);
}

try {
    System.out.println("Started..");
    System.out.println(future.get(3, TimeUnit.SECONDS));
    System.out.println("Finished!");
} catch (TimeoutException e) {
    System.out.println("Terminated!");
}

But this would not work for more than one thread. Maybe I have to put each thread in a List<Future> list and iterate over this list and set a timeout for each future object?

Any suggestions?

EDIT AFTER USING CountDownLatch:

CountDownLatch doneSignal = new CountDownLatch(partition.size());
List<Future<?>> tasks = new ArrayList<Future<?>>();
ExecutorService executor = Executors.newFixedThreadPool(8);
for (List<String> l : partition) {
    Runnable worker = new WorkerThread(l);
    tasks.add(executor.submit(doneSignal, worker));
}

doneSignal.await(1, TimeUnit.SECONDS);
if (doneSignal.getCount() > 0) {
    for (Future<?> fut : tasks) {
    if (!fut.isDone()) {
        System.out.println("Task " + fut + " has not finshed!");
        //fut.cancel(true) Maybe we can interrupt a thread this way?!
    }
    }
}

Works good so far.

So next question is how to interrupt a thread which is timed out? I try fut.cancel(true) and add following construct in some critical loops in the worker thread:

if(Thread.interrupted()) {
    System.out.println("!!Thread -> " + Thread.currentThread().getName() + " INTERRUPTED!!");
        return;
}

So the worker thread is "killed" after the timeout. Is this a good solution?

Furthermore: Is it possible to get the name of the thread which timed out over the Future interface? At the moment I have to print out the name in the if condition of the Thread.interrupted() construct.

Thanks for help!

Regards

4
  • 1
    Yes it works for more, just keep Futures in a List. Commented Jan 9, 2013 at 13:50
  • 4
    Please don't think about threads this way. There is something being done, and you want a timeout if it takes more than a certain amount of time. It's not whatever thread might happen to be doing that work, it's the work. Maybe two threads are cooperating on the work. Maybe no thread is working on that work at the time. But it's the work you want to stop or timeout or whatever, not the thread or threads that might or might not happen to be working on it. This subtle view shift is important to thinking correctly about threads so that you wind up with good designs. Commented Jan 9, 2013 at 13:57
  • 1
    @DavidSchwartz good point, however there may be situations were works are completely independent from one another. I don't know whether the OP actually though about this, but it looks like this is the case here. Commented Jan 9, 2013 at 13:58
  • @fge: It's not about the relationship of works to each other. It's about the concept of "work" (the thing that needs to get done) being distinct from the thread(s) that are doing it. If work is waiting for something, no thread may be associated with it. If work can be done concurrently, multiple threads may be cooperating to do it. When you are waiting for some work to be done, you shouldn't be thinking about what thread or threads, if any, are working on it. Commented Jan 10, 2013 at 19:47

2 Answers 2

3

Have you seen this? ExecutorService.invokeAll

It should be exactly what you want: Invoke a bundle of workers and have them timeout if taking too long.

EDIT after comment - (new idea): You can use a CountDownLatch to wait for the tasks to finish AND timeout via await(long timeout, TimeUnit unit)! You can then even do a shutdownNow and see which tasks have taken too long ...

EDIT 2:

To make it clearer:

  1. Have a CountDownLatch be count down by each Worker, when finished.
  2. In the main execution thread await with timeout on said latch.
  3. When that call returns, you can check the Latches's count to see if there has been the timeout hit (if it is >0).
  4. a) count = 0, all tasks finished in time. b) if not, loop the Futures and check their isDone. You don't have to call shutdown on the ExecutorService.
  5. Call shutdown if you do not need the Executor any longer.

Note: Workers can finish in the meantime between the timeout and calling their Future's isDone().

Sign up to request clarification or add additional context in comments.

6 Comments

Okay...Nevertheless I have to call "executor.shutdown()" to wait if the threads are finished at all, right?
Not necessarily. You could still cycle through the futures an poll isDone() or call get() on each Future or you could make use of a docs.oracle.com/javase/7/docs/api/java/util/concurrent/… I consider the latter the "nicest" way.
Ahh, ok very good. "CountDownLatch" looks very nice. You say (in your "edit" lines) that I can run shutdownNow after calling await. So the method shutdownNow will cancel all threads which are still running because of the set timeout? That is my next question because I find no way with invokeAll to find out which threads are "violating" the timeout. Maybe with the new approach it is possible?
Only slight change. You'll call await on the CountDownLatch instance with a timeout. That call will block until the timeout hits or the latch is down to 0. After that you can shutdownNow, which returns a list of ... ahhh just reading it's only the unstarted tasks that are being returned by shutdownNow. But you can still iterate the Futures and ask them if they are done :)
Okay, but also if I iterate over the Futures and ask them if they are done I have to call shutdown() or shutdownNow(). At the moment I get an "java.util.concurrent.CancellationException" when doing this without calling shutdown(): List<Future<String>> list = executor.invokeAll(tasks, 1, TimeUnit.SECONDS); for(Future<String> fut : list){ if(fut.isDone()) { System.out.println("Task " + fut.get() + " has finished."); } } The Future is returning a string with the Thread name. EDIT: WITHOUT USING "CountDownLatch"
|
0
Future future = executorService.submit(callable)
future.get(timeout, unit)

For more information see this link.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.