微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

CompletableFuture 在工作线程发送到睡眠状态后没有响应

如何解决CompletableFuture 在工作线程发送到睡眠状态后没有响应

我正在尝试了解 ConsumableFuture。 基本上,我向 ConsumableFuture 提供一个任务,然后让运行该任务的工作线程休眠 2 秒。我希望工作线程在 2 秒后恢复执行并返回结果。

public class CompletableFutureDemo {

    public static void main(String[] args) {
        
        System.err.println("Application started");
        
        CompletableFuture
            .supplyAsync(()->work1())
            .thenAccept(op-> System.out.println(op));
        
        System.err.println("Application ended");
    }
    
    public static int work1() {
        System.out.println(Thread.currentThread().getName());
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printstacktrace();
        }
        System.out.println("work1 called");
        return (int) (Math.random() * 100);
    }
}

输出

Application started
ForkJoinPool.commonPool-worker-1
Application ended

为什么工作线程没有恢复?

但是如果我从工作线程中删除 sleep 语句,那么我会得到所需的输出

Application started
ForkJoinPool.commonPool-worker-1
work1 called
Application ended
64

解决方法

正如@Slaw在评论中已经指出的那样,主线程在工作线程休眠时完成并退出应用程序,因此您可以调用join来保持主线程等待直到工作线程完成

System.err.println("Application started");

 CompletableFuture
            .supplyAsync(()->work1())
            .thenAccept(op-> System.out.println(op)).join();

System.err.println("Application ended");

输出:

ForkJoinPool.commonPool-worker-3
Application started
work1 called
12
Application ended

或者你可以让主线程在它工作完成后等待

  System.err.println("Application started");

  CompletableFuture<Void> completableFuture = CompletableFuture
            .supplyAsync(()->work1())
            .thenAccept(op-> System.out.println(op));

  System.err.println("Application ended");

  completableFuture.join();

输出:

ForkJoinPool.commonPool-worker-3
Application started
Application ended
work1 called
25

如果您有多个 CompletableFuture 对象,那么您可以使用 allOf 等待所有任务完成(但在后台每个可完成任务将异步执行)

CompletableFuture.allOf(completableFuture1,completableFuture1).join();
,

通过提供我自己的 Executor 实例,我实现了异步操作并避免将其标记为守护进程。 (任何口味的 Executor)

CompletableFuture
            .supplyAsync(()->work1(),Executors.newFixedThreadPool(2))
            .thenAccept(op-> System.out.println(op));

我认为这可以避免创建守护线程,类似于我们在 ExecutorServices 中所做的。

感谢@Slaw 提供有关守护进程线程的信息。我想了解更多为什么 ForkJoin 架构默认将线程标记为守护进程。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。