Java 可完成的未来:若干任务

Java 可完成的未来:若干任务,java,java-8,runnable,java-threads,completable-future,Java,Java 8,Runnable,Java Threads,Completable Future,如何使用5个CompletableFutures异步执行20个可运行任务(或1个任务20次) 这就是我得到的: Runnable task = () -> { long startTime = System.currentTimeMillis(); Random random = new Random(); while (System.currentTimeMillis() - startTime < 3000) {

如何使用5个CompletableFutures异步执行20个可运行任务(或1个任务20次)

这就是我得到的:

Runnable task = () -> {
        long startTime = System.currentTimeMillis();
        Random random = new Random();

        while (System.currentTimeMillis() - startTime < 3000) {
            DoubleStream.generate(() -> random.nextDouble())
                    .limit(random.nextInt(100))
                    .map(n -> Math.cos(n))
                    .sum();
        }
        System.out.println("Done");
    };

    for (int i = 0; i < 4; i++) {
        CompletableFuture<Void> future1 = CompletableFuture.runAsync(task);
        CompletableFuture<Void> future2 = CompletableFuture.runAsync(task);
        CompletableFuture<Void> future3 = CompletableFuture.runAsync(task);
        CompletableFuture<Void> future4 = CompletableFuture.runAsync(task);
        CompletableFuture<Void> future5 = CompletableFuture.runAsync(task);
        future1.get();
        future2.get();
        future3.get();
        future4.get();
        future5.get();
    }
Runnable任务=()->{
long startTime=System.currentTimeMillis();
随机=新随机();
而(System.currentTimeMillis()-startTime<3000){
DoubleStream.generate(()->random.nextDouble())
.限值(随机.下一个(100))
.map(n->Math.cos(n))
.sum();
}
系统输出打印项次(“完成”);
};
对于(int i=0;i<4;i++){
CompletableFuture1=CompletableFuture.runAsync(任务);
CompletableFuture2=CompletableFuture.runAsync(任务);
CompletableFuture3=CompletableFuture.runAsync(任务);
CompletableFuture4=CompletableFuture.runAsync(任务);
CompletableFuture5=CompletableFuture.runAsync(任务);
未来1.获取();
未来2.获取();
未来3.获取();
未来4.获得();
未来5.获得();
}
如果执行此代码,我可以看到它只异步运行3个future.get(): 3,然后在1 for()迭代中剩下的2


因此,我希望尽可能异步地完成所有20个任务

您可以使用allOf将多个任务同时作为一个任务运行。首先,我创建了5个任务的组合(与您的问题相同),但后来我添加了10个任务(只运行了两次),得到了一半的执行时间

for (int i = 0; i < 2; i++) {
   CompletableFuture<Void> future1 = CompletableFuture.runAsync(task);
   CompletableFuture<Void> future2 = CompletableFuture.runAsync(task);
  // and so on until ten  
   CompletableFuture<Void> future10 = CompletableFuture.runAsync(task);

   CompletableFuture<Void> combined = CompletableFuture.allOf(future1, future2, future3, future4, future5, future6, future7, future8, future9, future10);

   combined.get();
}
for(int i=0;i<2;i++){
CompletableFuture1=CompletableFuture.runAsync(任务);
CompletableFuture2=CompletableFuture.runAsync(任务);
//以此类推,直到十点
CompletableFuture10=CompletableFuture.runAsync(任务);
CompletableFuture合并=CompletableFuture.allOf(future1、future2、future3、future4、future5、future6、future7、future8、future9、future10);
combined.get();
}

将以下系统属性设置为希望公共分叉连接池使用的线程数:

java.util.concurrent.ForkJoinPool.common.parallelism 

原因是,在构建可完成的未来时,您没有指定自己的fork-join池,因此它隐式地使用

ForkJoinPool.commonPool()

请参见CompletableFuture的默认执行器是
ForkJoinPool
的公共池,该池的默认目标并行度与CPU核数减1相匹配。因此,如果您有四个内核,最多可以异步执行三个作业。因为您每5个作业强制等待一次完成,所以您将得到三个并行执行,然后在每个循环迭代中有两个并行执行

如果您想要获得一个特定的执行策略,比如您选择的并行性,最好的方法是指定一个正确配置的执行器。然后,您应该让执行器管理并行性,而不是在循环中等待

ExecutorService pool = Executors.newFixedThreadPool(5);

for (int i = 0; i < 20; i++) {
    CompletableFuture.runAsync(task, pool);
}
pool.shutdown();
pool.awaitTermination(1, TimeUnit.DAYS); // wait for the completion of all tasks
但当您的工作不涉及I/O或任何其他类型的等待响应时。释放CPU后,没有必要创建比CPU内核更多的线程。配置为处理器数量的池更可取

ExecutorService pool = Executors.newWorkStealingPool(
    Runtime.getRuntime().availableProcessors());
// schedule 20 jobs at return when all completed
pool.invokeAll(Collections.nCopies(20, Executors.callable(task)));
pool.shutdown();

在您的特殊情况下,这可能会运行得较慢,因为当线程比内核多时,作业会使用系统时间来显示运行得更快,但实际执行的工作会更少。但是对于普通的计算任务,这将提高性能。

也许下面的帖子有帮助:为什么关机后要等待终止?你不应该先等终止后再给执行人打电话关机吗?@FarazDurrani执行人不会关机,除非被告知这样做。因此,当没有人请求关闭时,等待终止只会等待指定的时间而没有任何好处。
ExecutorService pool = Executors.newCachedThreadPool();
// schedule 20 jobs and return when all completed
pool.invokeAll(Collections.nCopies(20, Executors.callable(task)));
pool.shutdown();
ExecutorService pool = Executors.newWorkStealingPool(
    Runtime.getRuntime().availableProcessors());
// schedule 20 jobs at return when all completed
pool.invokeAll(Collections.nCopies(20, Executors.callable(task)));
pool.shutdown();