我有以下代码:
public class Application1 {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(5);
List<Callable<Boolean>> callableTasks = new ArrayList<>();
callableTasks.add(new LogDownloadCallable());
callableTasks.add(new LogDownloadCallable());
callableTasks.add(new LogDownloadCallable());
callableTasks.add(new LogDownloadCallable());
callableTasks.add(new LogDownloadCallable());
List<Future<Boolean>> futures =null;
try {
futures = executorService.invokeAll(callableTasks, 1090, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
System.out.println("invokeall inturrupted !!");
}
executorService.shutdownNow();
}
}
class LogDownloadCallable implements Callable<Boolean> {
public Boolean call() throws Exception {
try{
//This for sure takes days to complete, so should through Cancellation exception because timeout on invokeall set to 1 minute
long val = 0;
for (long i = 0; i < Long.MAX_VALUE - 5000; i++) {
val += i;
}
System.out.println("complete");
}catch(Exception e){
System.out.println("Exception ! " +e.toString()+ Thread.currentThread().getId());
return false;
}
return true;
}
}我希望在1090毫秒超时后得到"java.lang.InterruptedException"。但这并不会发生。有人能告诉我为什么吗?如果我在public Boolean call() throws Exception {的try块中,在for循环之前放入一个Thread.sleep(2000);,那么我得到的是InterruptedException。这种行为很奇怪。附言:这只是一个我虚构的例子来展示我的问题。
发布于 2018-02-14 03:23:58
取消是通过向执行任务的线程发送中断来实现的。然而,一如既往,通过中断取消是一项合作努力。被中断的任务,应该定期检查它正在运行的线程的中断标志,然后在最方便的时候停止运行。一种常见的误解是,认为中断线程会自动导致在其上运行的代码中抛出InterruptedException。
如果任务调用阻塞方法(您可以识别它们,因为它们被声明为抛出InterruptedException),它将通过处理异常来强制处理被中断的线程。Thread.sleep()就是这样一种方法,这就是当您将它添加到代码中时会看到超时工作的原因。
如果任务不调用任何阻塞方法,例如当您不在代码中调用Thread.sleep()时,让任务知道它被中断的唯一方法是检查线程的中断标志本身。对于在无限(或长)循环中运行的代码,这通常是在每次迭代中完成一次。
请注意,一些方法会阻塞线程上运行的代码,但也不会响应中断(例如阻塞IO)。他们不会抛出InterruptedException,而是会高兴地继续做他们正在做的事情。让这样的任务对取消做出更好的响应是比较棘手的,可能会因情况不同而不同。
在方便的情况下尽早停下来可能意味着很多事情。对于某些任务,这可能意味着立即停止。对于其他代码,这可能意味着清除中断标志,运行到完成,然后再次设置中断标志并返回其结果。
对于您的示例代码,它显然将是前一种选择。
public Boolean call() throws Exception {
long val = 0;
for (long i = 0; i < Long.MAX_VALUE - 5000; i++) {
if (Thread.currentThread().isInterrupted()) { // explicit check for cancellation
System.out.println("Exception ! " +e.toString()+ Thread.currentThread().getId());
return false;
}
val += i;
}
System.out.println("complete");
return true;
}发布于 2018-02-13 03:57:38
简而言之,你不能中断没有抛出java.lang.InterruptedException的任务。如果你有下面的代码
class LogDownloadCallable implements Callable<Boolean> {
public Boolean call() throws Exception {
try {
long val = 0;
for (long i = 0; i < Long.MAX_VALUE - 5000; i++) {
val += i;
Thread.sleep(1); // throws java.lang.InterruptedException
}
System.out.println("complete");
} catch (Exception e) {
System.out.println("Exception ! " + e.toString() + Thread.currentThread().getId());
return false;
}
return true;
}}
你的应用程序将会像你希望的那样工作。在您的情况下,我建议您使用Daemon线程,这些线程可以立即停止。如何使用Daemon线程watch here设置ExecutorService。以及有关Java可用here中中断的更多详细信息。
发布于 2018-02-13 06:56:42
对于这种情况,对我来说起作用的是用Guava的ThreadFactoryBuilder类创建线程。
ExecutorService executorService = Executors.newFixedThreadPool(5, new ThreadFactoryBuilder().setDaemon(true).build());创建的线程是守护进程,它们在超时后被杀死。在线程中断的情况下,当我执行future.get()时,我会得到CancellationException。
https://stackoverflow.com/questions/48753932
复制相似问题