繁体   English   中英

CompletableFuture.get 不等待最终块

[英]CompletableFuture.get not waiting for final block

我有一个自定义的 ExecutorService,

class CustomExecutorService implements ExecutorService {

        ExecutorService delegate;

        public CustomExecutorService(ExecutorService delegate){
            this.delegate = delegate;
        }
        // All methods are just delegated to the delegate except execute
        
        public void execute(Runnable command) {
            this.delegate.execute(wrapRunnable(command));
        }

        private Runnable wrapRunnable(final Runnable command) {
            return () -> {
                try {
                    command.run();
                } finally {
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("Finalizer done.");
                }
            };
        }
    }

现在这是我的测试代码,

ExecutorService executorService = new CustomExecutorService(Executors.newCachedThreadPool());
CompletableFuture.runAsync(() -> System.out.println("Command done."), executorService).get();
System.out.println("Main Thread Done.");

现在我希望发生以下输出,

Command done.
Finalizer done. //After a wait of 2 seconds
Main Thread Done.

然而正在发生的事情是,

Command done.
Main Thread Done.

它甚至没有等待finally块并且主线程正在退出。 我无法解释这种行为,因为CompletableFuture#get应该是阻塞的,但它似乎没有等待finallly阻塞。

据我所知, finally不能保证,如果要执行finally是要由守护线程和所有其他非守护线程退出前执行finally被调用。 然而 ExecutorService 线程是非守护线程,所以finally应该被执行。

我在corretto-11.0.11上运行这个

当您运行CompletableFuture.runAsync它将您的Runnable包装在一个运行 runnable 的任务(源代码中的AsyncRun )中,然后将 CompletableFuture 标记为完成。 这是传递给执行者的内容。

在您的执行程序中,您正在包装任务,因此在您的finally块运行时,未来已被标记为完成,这就是get()在该点之后立即返回的原因。

查看CompletableFuture 1627行(Jdk 1.8)的源码如下:

public void run() {
    CompletableFuture<Void> d; Runnable f;
        if ((d = dep) != null && (f = fn) != null) {
            dep = null; fn = null;
            if (d.result == null) {
                try {
                    f.run();
                    d.completeNull(); // line 1627
                } catch (Throwable ex) {
                    d.completeThrowable(ex);
                }
            }
            d.postComplete();
        }
    }
}

Runnable f完成后, CompletableFuture 的结果将被设置为null ,然后get()方法将不再被阻塞。 在你的情况下Runnable f等于System.out.println("Command done.")

可以在CompletableFuture runAsync(Runnable runnable, Executor executor)的入口处设置断点,一CompletableFuture runAsync(Runnable runnable, Executor executor)调试,你会发现什么时候设置了 CompletableFuture 的结果。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM