程序永远不会在 java 中的 TimeoutException 上结束

Program never ends on TimeoutException in java

我正在尝试一个 java 程序来理解 Future 的工作原理。

我写了下面的程序,它永远不会结束。如果我在 Thread.sleep() 中输入一个小于 10 的值,那么它有效但不适用于值 >=10.

我知道导致问题的部分可能是 future.get 调用。

然而,经过进一步分析,我尝试的是处理所有异常,而不是让 jvm 处理它们。

例如:

现在它正常终止了。

我做了进一步的检查,发现如果我抛出 ExecutionExceptionInterruptedException 并处理 TimeoutException 它再次正常工作。 这里奇怪的部分是我必须强制处理 TimeoutException,否则它不会工作。我不太确定为什么这种奇怪的行为会持续存在。

我正在使用 OpenJDK 15。

如果有人想在这里尝试代码片段:

import java.util.concurrent.*;

public class FixedThreadPoolExecutorDemo2 {

    public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        workWithFutureCallable(executorService);
        executorService.shutdownNow();
    }

    private static void workWithFutureCallable(ExecutorService executorService) throws ExecutionException, InterruptedException, TimeoutException {

        Future<Integer> myOtherFuture = executorService.submit(() -> {
            try {
                Thread.sleep(109);
            } catch (InterruptedException e) {
            }
            return 1000;
        });
        System.out.println("myOtherFuture  should be cancelled if running for more than specified time. ->" + myOtherFuture.get(10, TimeUnit.MILLISECONDS));

    }
}

TimeoutException 未在 main 中捕获,因此 main 也在没有 调用 shutdownNow 的情况下突然终止 。主线程已终止,但 Executors 创建的线程默认为非守护进程,因此虚拟机未关闭,Executors 个线程继续 运行.

解决方案:

    public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        try {
            workWithFutureCallable(executorService);
        } finally {
            executorService.shutdownNow();
        }
    }

实施 ThreadFactory 来创建守护线程并使用它来获取服务:

        ExecutorService executorService = Executors.newFixedThreadPool(2, r -> {
            var thread = new Thread(r);
            thread.setDaemon(true);
            return thread;
        });

甚至更好,至少在生产代码中,捕获并处理 Exceptions(连同 finally 块。)