为什么 ExecutorService 在 invokeAny returns 结果后没有关闭?
Why ExecutorService is not shutdown after invokeAny returns a result?
当我在 Java 中试验 Future 和 Callable 时,我得到了一个以我目前的理解无法理解的结果。 以下场景仅供演示。
据我了解,当通过 invokeAny()
调用将 Callable
的集合提交给 ExecutorService
时,第一个 ExecutorService
returns结果它从他们身上消失了。检索结果后,我调用 executorService.shutDown()
,我希望它关闭 executorService,因为它已经 return 结果。但是,对于以下情况,程序会停止。我也试过打电话 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);
}
随着这一改变,naiveFibonacci
任务将在 optimizedFibonacci
产生结果后立即停止。
更改:正如 Holger 评论的那样,使用 Thread.interrupted()
优于 Thread.currentThread().isInterrupted()
,因为 if
语句中的代码将处理中断。
当我在 Java 中试验 Future 和 Callable 时,我得到了一个以我目前的理解无法理解的结果。 以下场景仅供演示。
据我了解,当通过 invokeAny()
调用将 Callable
的集合提交给 ExecutorService
时,第一个 ExecutorService
returns结果它从他们身上消失了。检索结果后,我调用 executorService.shutDown()
,我希望它关闭 executorService,因为它已经 return 结果。但是,对于以下情况,程序会停止。我也试过打电话 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);
}
随着这一改变,naiveFibonacci
任务将在 optimizedFibonacci
产生结果后立即停止。
更改:正如 Holger 评论的那样,使用 Thread.interrupted()
优于 Thread.currentThread().isInterrupted()
,因为 if
语句中的代码将处理中断。