Java 未来<;T>;。当runnable在单独的executor服务上运行时引发异常时,get()被卡住了?

Java 未来<;T>;。当runnable在单独的executor服务上运行时引发异常时,get()被卡住了?,java,future,executorservice,freeze,executor,Java,Future,Executorservice,Freeze,Executor,这里有一个复制品: import java.util.concurrent.*; public class Main { public static void main(String[] args) throws ExecutionException, InterruptedException { System.out.println("Hello!"); ExecutorService exec = Executors.newSingleThrea

这里有一个复制品:

import java.util.concurrent.*;

public class Main {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("Hello!");

        ExecutorService exec = Executors.newSingleThreadExecutor();

        Future<Integer> f = exec.submit(() -> x());

        f.get();

        System.out.println("f.get() returned");

        exec.shutdownNow();

        System.out.println("Good bye!");
    }

    private static Integer x() {
        throw new RuntimeException("An unfortunate event");
    }
}
import java.util.concurrent.*;
公共班机{
公共静态void main(字符串[]args)引发ExecutionException、InterruptedException{
System.out.println(“你好!”);
ExecutorService exec=Executors.newSingleThreadExecutor();
Future f=exec.submit(()->x());
f、 get();
System.out.println(“f.get()返回”);
exec.shutdownNow();
System.out.println(“再见!”);
}
私有静态整数x(){
抛出新的RuntimeException(“一个不幸的事件”);
}
}
输出仅显示“Hello!”和异常stacktrace,然后程序将永远挂起

下面的更改解决了这个问题,但是您知道为什么执行挂起在上面的代码中吗

使用公共线程池不会挂起:

Future<Integer> f = ForkJoinPool.commonPool().submit(() -> x());
Future f=ForkJoinPool.commonPool().submit(()->x());
围绕try/catch包装调用可以让应用程序正常退出:

Future<Integer> f = exec.submit(() -> x());

try {
    f.get();
} catch (Exception ex) {
    ex.printStackTrace();
}
Future f=exec.submit(()->x());
试一试{
f、 get();
}捕获(例外情况除外){
例如printStackTrace();
}

始终很难找到一个好的
示例,最后尝试
及其适当用法。我想是这样的

try {
    f.get();
    System.out.println("f.get() returned");
} finally {
    exec.shutdownNow();
}

f.get()引发的异常未处理,主线程失败。但是应用程序仍然包含可由
ExecutorService
管理的非守护进程线程,您无法直接访问这些线程。

如预期的那样,在
get()
中从main抛出异常。这意味着执行不会超过该行。Executor服务从未关闭,因此您有一个正在运行的非守护进程线程。JVM不会退出。你能解释一下你期望的行为吗?@Boristeider既然你指出了,那就是。。。显而易见。我需要更多的睡眠/咖啡:-)对于这样的控制台应用程序,是否有一种实用的方法可以安全地杀死线程池,这样应用程序除了捕获异常外还可以退出?也许尝试/最后确保线程池关闭?如果您希望JVM退出,即使任务仍在运行,那么只需使用守护进程线程。否则,你就需要使用关机挂钩之类的工具了。或者,使用一个像Spring Boot这样的框架,它可以为你处理很多这方面的事情。但是它是一个很大的框架,所以您需要一个相当复杂的应用程序,然后才值得引入类似的应用程序。CommonPool默认使用守护线程。在这种情况下更简单-在调用
get()
之前提交任务后调用
关闭
。谢谢!这很有效。我选择在线程池中使用守护进程线程,因为我并不真正希望它们干净地退出。