Java:为线程池中的线程设置超时

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14236654/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 15:33:45  来源:igfitidea点击:

Java: Set timeout for threads in a ThreadPool

javamultithreadingtimeout

提问by sk2212

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 futureobject?

但这不适用于多个线程。也许我必须将每个线程放在一个List<Future>列表中并遍历该列表并为每个future对象设置超时?

Any suggestions?

有什么建议?

EDIT AFTER USING CountDownLatch:

使用 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:

那么下一个问题是如何中断一个超时的线程?我尝试fut.cancel(true)在工作线程的一些关键循环中添加以下构造:

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 Futureinterface? At the moment I have to print out the name in the if condition of the Thread.interrupted()construct.

此外:是否可以获取通过Future接口超时的线程的名称?目前我必须在Thread.interrupted()构造的 if 条件中打印出名称。

Thanks for help!

感谢帮助!

Regards

问候

采纳答案by Fildor

Have you seen this? ExecutorService.invokeAll

你见过这个吗?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 CountDownLatchto 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 ...

评论后编辑 -(新想法):您可以使用CountDownLatch等待任务完成并通过await(long timeout, TimeUnit unit)! 然后您甚至可以执行 shutdownNow 并查看哪些任务花费了太长时间......

EDIT 2:

编辑2:

To make it clearer:

为了更清楚:

  1. Have a CountDownLatch be count down by each Worker, when finished.
  2. In the main execution thread awaitwith 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.
  1. 完成后,让每个 Worker 对 CountDownLatch 进行倒计时。
  2. 在主执行线程中await,所述闩锁超时。
  3. 当该调用返回时,您可以检查锁存器的计数以查看是否存在超时命中(如果大于 0)。
  4. a) count = 0,所有任务按时完成。b) 如果没有,循环 Futures 并检查它们的isDone. 您不必在 ExecutorService 上调用 shutdown。
  5. 如果您不再需要 Executor,请调用 shutdown。

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

注意:Worker 可以在超时和调用其 Future 的 isDone() 之间的这段时间内完成。