当我在Java中尝试Future和Callable时,我得到了一个我目前无法理解的结果以下场景仅用于演示
根据我的理解,当Callable
的集合通过invokeAny()
调用提交给ExecutorService
时,ExecutorService
会返回它从中得到的第一个结果。检索结果后,我调用executorService.shutDown()
,我希望它关闭executorService,因为它已经返回了一个结果。但是,对于以下情况,程序将停止。我也试过打executorService.shutDownNow()
,但没有成功。
我尝试了同样的例子,使用了两个方法,它们分别只让线程休眠1000
和5000
秒,在第一个方法完成后,休眠executorService.shutDown()
按预期工作。
我唯一的猜测是shutDown()
或shutDownNow()
不能像cancel(mayInterruptIfRunning=true)
那样中断已经在执行的线程。
有人能解释一下这里发生了什么吗?我猜对了吗?
下面是一个例子:
public class InvokeAnyExample {
public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
int N = 50; // If I set N = 10, program exits successfully.
ExecutorService executorService = Executors.newFixedThreadPool(2);
Callable<Long> naiveFibonacci = () -> {
log("Naive Fibonacci");
long result = fibonacciNaive(N);
log("Naive Fibonacci Finished");
return result;
};
Callable<Long> optimizedFibonacci = () -> {
log("Optimized Fibonacci");
long[] cache = new long[1000];
Arrays.fill(cache, -1);
long result = fibonacciOptimized(N, cache);
log("Optimized Fibonacci Finished");
return result;
};
Long result = executorService.invokeAny(Arrays.asList(naiveFibonacci, optimizedFibonacci), 5, TimeUnit.SECONDS);
log(String.valueOf(result));
executorService.shutdown();
// executorService.shutdownNow();
}
private static long fibonacciNaive(int n) {
if (n == 0 || n == 1) return n;
return fibonacciNaive(n - 1) + fibonacciNaive(n - 2);
}
private static long fibonacciOptimized(int n, long[] cache) {
if (n == 0 || n == 1) return n;
if (cache[n] != -1) return cache[n];
long result = fibonacciOptimized(n - 1, cache) + fibonacciOptimized(n - 2, cache);
cache[n] = result;
return result;
}
private static void log(String message) {
String prefix = Thread.currentThread().getName();
System.out.println(String.format("In Thread (%s) : %s", prefix, message));
}
}
这是输出:
In Thread (pool-1-thread-2) : Optimized Fibonacci
In Thread (pool-1-thread-1) : Naive Fibonacci
In Thread (pool-1-thread-2) : Optimized Fibonacci Finished
In Thread (main) : 12586269025
--- PROGRAM HALTS
正如Mark Rotteveel在评论中所写:
naiveFibonacci
任务不可中断。它不调用任何检查线程中断状态的方法,fibonacciNaive()
方法本身也不检查线程的中断状态。
如果您想使fibonacciNaive()
方法可中断,您可以将其更改为:
private static long fibonacciNaive(int n) throws InterruptedException {
if (n == 0 || n == 1) return n;
if (Thread.interrupted()) {
log("interrupt detected");
throw new InterruptedException();
}
return fibonacciNaive(n - 1) + fibonacciNaive(n - 2);
}
一旦optimizedFibonacci
产生结果,naiveFibonacci
任务就会停止。
更改:正如Holger所评论的,使用Thread.interrupted()
比使用Thread.currentThread().isInterrupted()
更可取,因为if
语句中的代码将处理中断。