线程与 CompletableFuture

Thread vs CompletableFuture

将代码直接传递给线程与使用 CompletableFuture 相比有什么优势?

Thread thread = new Thread(() -> {do something});
thread.start();

VS

CompletableFuture<Void> cf1 =  
     CompletableFuture.runAsync(() -> {do something}); 

CompletableFuture.runAsync(...) 管理的 forkJoin-Pool 中运行 Runnable,而 new Thread() 创建一个新线程, 你有管理.

"is managed"是什么意思,它是预分配的,线程是在JVM中共享的。当 runnable 完成时,线程可以被其他 runnable 重用。这可以更好地利用资源,特别是因为线程实例化是一项昂贵的操作 - 不仅是对象,还有一些额外的非堆内存 - 线程堆栈 - 必须分配。

@Gerald Mücke 已经提到了重要的区别:

CompletableFuture.runAsync(...) runs the Runnable in the forkJoin-Pool which is managed, while new Thread() creates a new thread which you have to manage.

CompletableFuture 将使用由 ThreadPool(默认或自定义)管理的线程。

不过,我觉得下面两点也是应该考虑的。

第一个

CompletableFuture 有很多简单易懂的方法将不同的异步计算链接在一起,引入异步比直接使用线程.

CompletableFuture[] futures = IntStream.rangeClosed(0, LEN).boxed()
            .map(i -> CompletableFuture.supplyAsync(() -> runStage1(i), EXECUTOR_SERVICE))
            .map(future -> future.thenCompose(i -> CompletableFuture.supplyAsync(() -> runStage2(i), EXECUTOR_SERVICE)))
            .toArray(size -> new CompletableFuture[size]);
CompletableFuture.allOf(futures).join();

第二

你永远不应该忘记处理异常;使用 CompletableFuture,你可以像这样直接处理它们:

completableFuture.handle((s, e) -> e.toString()).join()

或者以这种方式利用它们来中断计算:

completableFuture.completeExceptionally(new RuntimeException("Calculation failed!"));

虽然使用 Thread.

很容易遇到一些严重的问题

CompletableFuture 是一个使用默认 ForkJoinPool(大小等于 CPU 的线程池)的承诺,除非提供另一个线程池。一个线程池将包含 n 个或更多数量的线程。