线程与可操作未来
2022-09-01 11:57:20
与改用ComppletableFuture相比,直接将代码传递到线程有什么好处?
Thread thread = new Thread(() -> {do something});
thread.start();
与
CompletableFuture<Void> cf1 =
CompletableFuture.runAsync(() -> {do something});
与改用ComppletableFuture相比,直接将代码传递到线程有什么好处?
Thread thread = new Thread(() -> {do something});
thread.start();
与
CompletableFuture<Void> cf1 =
CompletableFuture.runAsync(() -> {do something});
CompletableFuture.runAsync(...)
在被管理的 forkJoin-Pool 中运行 Runnable,同时创建一个您必须管理的新线程。new Thread()
“被管理”是什么意思,它是预先分配的,线程在JVM中共享。当 runnable 完成后,该线程可以重新用于其他 runnable。这样可以更好地利用资源,特别是因为线程实例化是一个昂贵的操作 - 不仅是对象,还有一些额外的非堆内存 - 线程堆栈 - 必须分配。
@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!"));
虽然你很容易遇到一些严重的问题使用线程。