![](/img/trans.png)
[英]Java how to timeout a thread WITHOUT using future.get and without blocking parent thread
[英]How to end a task(timeout a thread) (by rising interrupt) using executor.execute and future.get() without blocking the main thread
我尝试在执行器服务中使用未来,它可以在不阻塞主线程的情况下工作。 然而,这最终会创建双倍数量的线程,这是不可取的。 在下面的代码中,我能够在没有阻塞的情况下使用 future.get() 但我必须创建双倍数量的线程
for (int i : array) {
executor.execute(() -> {
Future f = new FutureTask(() -> {
Goring goring = new Goring();
goring.goring(i);
}, null);
Thread thread = new Thread((Runnable) f);
thread.start();
try {
f.get(1, TimeUnit.NANOSECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException|RuntimeException e) {
// TODO Auto-generated catch block
// System.out.println(e.getMessage());
e.printStackTrace();
f.cancel(true);
}
});
}
executor.shutdown();
}
通常我会推荐使用ExecutorService.invokeAll ,它允许提交任意数量的超时任务,并在超时到期时取消任何尚未完成的任务。
但是您在评论中声明您希望能够在较小的并行组中提交任务,例如一次不超过三个并行运行。
您可以创建具有有限并行度的线程池:
ExecutorService executor = Executors.newFixedThreadPool(3);
这里的挑战是您希望在任务启动时开始超时,而不是在提交任务时。 由于提交的任务无法访问自己的 Future,我将使用SynchronousQueue来等待从提交线程传递的 Future:
ScheduledExecutorService cancelScheduler =
Executors.newSingleThreadScheduledExecutor();
for (int i : array) {
SynchronousQueue<Runnable> cancelQueue = new SynchronousQueue<>();
Future<?> task = executor.submit(() -> {
Runnable canceler = cancelQueue.take();
cancelScheduler.schedule(canceler, 5, TimeUnit.SECONDS);
Goring goring = new Goring();
goring.goring(i);
return null;
});
cancelQueue.put(() -> task.cancel(true));
}
executor.shutdown();
cancelScheduler.shutdown();
顾名思义, Executors.newSingleThreadScheduledExecutor()只使用一个线程进行所有调度,这非常适合您的目的,因为计划任务只调用 Future.cancel,所花费的时间可以忽略不计。
return null;
在任务中,从 lambda 返回一个值使其成为 Callable 而不是 Runnable。 (Runnable 的run
方法有一个返回类型void
,所以返回值的存在告诉编译器这个 lambda 不可能代表一个 Runnable。)这意味着它的签名隐含地throws Exception
,所以没有必要捕获 InterruptedException可能由cancelQueue.take()
抛出。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.