线程与可操作未来

与改用ComppletableFuture相比,直接将代码传递到线程有什么好处?

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

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

答案 1

CompletableFuture.runAsync(...)被管理的 forkJoin-Pool 中运行 Runnable,同时创建一个您必须管理的新线程。new Thread()

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


答案 2

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

CompletableFuture.runAsync(...) 在 forkJoin-Pool 中运行 Runnable,该池由管理,而 new Thread() 会创建一个您必须管理的新线程。

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

不过,我认为以下两点也是应该考虑的。

第一

CompletableFuture有许多易于理解的方法将不同的异步计算链接在一起,这使得引入异步性比直接使用Thread更容易。

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();

第二

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

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

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

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

虽然你很容易遇到一些严重的问题使用线程