用于基本任务的Java 8 Concurrency最简单的规范形式

时间:2016-03-17 19:22:10

标签: java concurrency java-8 completable-future

我有两个问题: 1.在Java 8中将Callable作为任务运行,捕获和处理结果的最简单的规范形式是什么? 2.在下面的示例中,在所有任务完成之前,保持主进程打开的最佳/最简单/最清晰的方法是什么?

这是我到目前为止的例子 - 这是Java 8中最好的方法还是有更基本的东西?

import java.util.*;
import java.util.concurrent.*;
import java.util.function.*;

public class SimpleTask implements Supplier<String> {
  private SplittableRandom rand = new SplittableRandom();
  final int id;
  SimpleTask(int id) { this.id = id; }
  @Override
  public String get() {
    try {
      TimeUnit.MILLISECONDS.sleep(rand.nextInt(50, 300));
    } catch(InterruptedException e) {
      System.err.println("Interrupted");
    }
    return "Completed " + id + " on " +
      Thread.currentThread().getName();
  }
  public static void main(String[] args) throws Exception {
    for(int i = 0; i < 10; i++)
      CompletableFuture.supplyAsync(new SimpleTask(i))
        .thenAccept(System.out::println);
    System.in.read(); // Or else program ends too soon
  }
}

有更简单,更清晰的Java-8方法吗?我如何消除System.in.read()支持更好的方法?

2 个答案:

答案 0 :(得分:5)

等待完成多个CompletableFuture实例的规范方法是通过CompletableFuture.allOf创建一个新的实例,具体取决于所有实例。您可以使用这个新的未来等待其完成或安排新的后续操作,就像使用任何其他CompletableFuture一样:

CompletableFuture.allOf(
    IntStream.range(0,10).mapToObj(SimpleTask::new)
             .map(s -> CompletableFuture.supplyAsync(s).thenAccept(System.out::println))
             .toArray(CompletableFuture<?>[]::new)
).join();

当然,如果您放弃为每个任务分配唯一ID,它总是变得更简单。由于您的第一个问题是关于Callable,因此我将演示如何通过Callable轻松提交ExecutorService的多个类似任务:

ExecutorService pool = Executors.newCachedThreadPool();
pool.invokeAll(Collections.nCopies(10, () -> {
    LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(
            ThreadLocalRandom.current().nextInt(50, 300)));
    final String s = "Completed on "+Thread.currentThread().getName();
    System.out.println(s);
    return s;
}));
pool.shutdown();

Executors.newCachedThreadPool()返回的执行程序服务未被共享,即使您忘记调用shutDown()也不会保持活动状态,但在所有线程终止之前最多可能需要一分钟。< / p>

因为你的第一个问题字面上是:“在Java 8中运行Callable作为任务的最简单的规范形式是什么,捕获并处理结果?”,答案可能是最简单的表单仍然直接调用它的call()方法,例如

Callable<String> c = () -> {
    LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(
            ThreadLocalRandom.current().nextInt(50, 300)));
    return "Completed on "+Thread.currentThread().getName();
};
String result = c.call();
System.out.println(result);

没有更简单的方法......

答案 1 :(得分:4)

考虑将期货收集到列表中。然后,您可以在每个未来使用join()等待它们在当前线程中完成:

List<CompletableFuture<Void>> futures = IntStream.range(0,10)
        .mapToObj(id -> supplyAsync(new SimpleTask(id)).thenAccept(System.out::println))
        .collect(toList());

futures.forEach(CompletableFuture::join);