线程与CompletableFuture

Sag*_*gar 13 java multithreading java-8 completable-future

将代码直接传递给线程vs使用CompletableFuture的优势是什么?

Thread thread = new Thread(() -> {do something});
thread.start();
Run Code Online (Sandbox Code Playgroud)

VS

CompletableFuture<Void> cf1 =  
     CompletableFuture.runAsync(() -> {do something}); 
Run Code Online (Sandbox Code Playgroud)

Ger*_*cke 16

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

什么是"被管理"的意思,它的预分配和线程在JVM共享.当runnable完成后,该线程可以重用于其他runnables.这样可以更好地利用资源,特别是当线程实例化是一项昂贵的操作时 - 不仅要对象,而且还要分配一些额外的非堆内存 - 线程堆栈.

  • 这里的一些陈述似乎有点过于笼统(@Cargeh和詹姆斯大).线程不仅用于利用可用的处理资源(核心),还用于隐藏延迟或执行非阻塞操作 - *即使(新)线程主要等待*(例如,对于IO).拥有一个带有`n`线程的池是没有意义的,它们都在等待(不存在的)第n + 1个线程应该做的事情.当然,这些东西通常被抽象层和库隐藏.但是手动创建新线程*可以*非常好 - 即使您"经验丰富". (5认同)
  • Re,"......你必须管理它." 不,你没有_have_来管理它.您可以创建一个新线程,启动它,然后忘记它.创建和销毁新线程的成本没有惩罚_except_. (4认同)

Hea*_*ren 8

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

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

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();
Run Code Online (Sandbox Code Playgroud)

第二

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

completableFuture.handle((s, e) -> e.toString()).join()
Run Code Online (Sandbox Code Playgroud)

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

completableFuture.completeExceptionally(new RuntimeException("Calculation failed!"));
Run Code Online (Sandbox Code Playgroud)

而使用Thread很容易遇到一些严重的问题。