Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 线程与可完成的未来_Java_Multithreading_Java 8_Completable Future - Fatal编程技术网

Java 线程与可完成的未来

Java 线程与可完成的未来,java,multithreading,java-8,completable-future,Java,Multithreading,Java 8,Completable Future,与使用CompletableFuture相比,直接将代码传递给线程有什么好处 Thread thread = new Thread(() -> {do something}); thread.start(); VS CompletableFuture cf1= runAsync(()->{do something}); CompletableFuture.runAsync(…)在被管理的forkJoin池中运行Runnable,而new Thread()创建您必须管理的新线程 “被管理”

与使用CompletableFuture相比,直接将代码传递给线程有什么好处

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

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

CompletableFuture.runAsync(…)
在被管理的forkJoin池中运行Runnable,而
new Thread()
创建您必须管理的新线程


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

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

runAsync(…)在被管理的forkJoin池中运行Runnable,而new Thread()创建一个必须管理的新线程

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

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

弗斯特 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!"));

虽然使用线程很容易遇到一些严重问题,但CompletableFuture承诺使用默认的ForkJoinPool(大小等于CPU数量的线程池),除非提供另一个线程池。一个线程池将包含n个或更多的线程。

如果我使用
线程,我还必须做些什么。从管理角度来说,开始使用
方法?Re“…你必须管理它。”不,你不必管理它。您可以创建一个新线程,启动它,然后忘记它。除了创建和销毁新线程的费用外,没有其他惩罚。@jameslarg谢谢!从来没有直接使用过线程,总是使用执行器,所以我没有意识到这一点。@jameslarge“除了创建和销毁线程的成本外,没有其他惩罚”,你让人觉得每个人都有无限的内核,而运行线程的成本是零。嗯,这需要CPU时间,这也是使用poolsSome语句的原因之一。这里的语句似乎有点过于泛化了(@Cargeh和james large)。线程不仅用于利用可用的处理资源(核心),还用于隐藏延迟或执行非阻塞操作——即使(新)线程主要在等待(例如IO)。拥有一个包含
n
线程的池是没有意义的,这些线程都在等待(不存在的)
n+1
第个线程应该做的事情。当然,这些东西通常被抽象层和库隐藏起来。但是手动创建一个新线程是非常好的——即使你“有经验”。
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();