我一直在使用Java 8中的CompletionStage / CompletableFuture进行异步处理,这非常有效。但是,有时我想要一个阶段来执行迭代器/项目流的异步处理,似乎没有办法做到这一点。
具体来说,Stream.forEach()具有语句,在调用之后所有项都已处理完毕。我想要相同的东西,但改为使用CompletionStage,例如:
CompletionStage<Void> done = stream.forEach(...);
done.thenRun(...);
如果Stream由异步流式传输结果支持,那么等待它在上面的代码本身中完成要好得多。
是否有可能以某种方式使用当前的Java 8 API构建它?解决方法?
答案 0 :(得分:21)
据我所知,streams API不支持异步事件处理。听起来你想要像Reactive Extensions for .NET这样的东西,它有一个名为RxJava的Java端口,由Netflix创建。
RxJava支持许多与Java 8流相同的高级操作(例如map和filter),并且是异步的。
更新:现在正在开展reactive streams计划,看起来JDK 9将通过Flow类至少支持部分内容。
答案 1 :(得分:7)
正如@KarolKrol所暗示,您可以使用CompletableFuture
的流来完成。
有一个基于JDK8流构建的库,以便于处理名为cyclops-react的CompletableFuture
流。
要编写你的流你可以使用cyclops-react的流畅的promise ike API,或者你可以使用simple-react的Stage
s。
答案 2 :(得分:3)
cyclops-react(我是这个库的作者),提供了一个用于处理Streams的StreamUtils类。 它提供的功能之一是futureOperations,它提供对标准Stream终端操作(然后是一些)的访问 - Stream是异步执行的,结果在CompletableFuture中返回。 .e.g
Stream<Integer> stream = Stream.of(1,2,3,4,5,6)
.map(i->i+2);
CompletableFuture<List<Integer>> asyncResult = StreamUtils.futureOperations(stream,
Executors.newFixedThreadPool(1))
.collect(Collectors.toList());
还有一个包含Stream的概念类ReactiveSeq并提供相同的功能,并提供了一个不错的流畅API
CompletableFuture<List<Integer>> asyncResult = ReactiveSeq.of(1,2,3,4,5,6)
.map(i->i+2)
.futureOperations(
Executors.newFixedThreadPool(1))
.collect(Collectors.toList());
正如Adam所指出的那样cyclops-react FutureStreams旨在异步处理数据(通过将Futures和Streams混合在一起) - 它特别适用于涉及阻塞I / O的多线程操作(例如读取文件,进行db调用,进行休息调用等。)
答案 3 :(得分:1)
可以生成一个流,将每个元素映射到CompletionStage
,然后使用CompletionStage.thenCombine()
收集结果,但是生成的代码将不会更简单,因此使用simple就像这样。
CompletionStage<Collection<Result>> collectionStage =
CompletableFuture.completedFuture(
new LinkedList<>()
);
for (Request request : requests) {
CompletionStage<Result> resultStage = performRequest(request);
collectionStage = collectionStage.thenCombine(
resultStage,
(collection, result) -> {
collection.add(result);
return collection;
}
);
}
return collectionStage;
这个例子可以很容易地转换为功能性,而不会失去可读性。但是使用流的reduce
或collect
需要额外的不太好的代码。
更新:CompletableFuture.allOf
和CompletableFuture.join
提供了另一种更易读的方式,可将未来结果的收集转换为未来的结果集合。
答案 4 :(得分:0)
如前所述,使用反应式编程:
Maven:
groupId:org.projectreactor
artifactId:反应器弹簧
例:
Flux.fromIterable(Arrays.asList("een", "twee"))
.flatMap(string -> translateDutchToEnglish(string))
.parallel()
.runOn(Schedulers.parallel())
.sequential()
.collectList()
.block();
它的作用是创建一个Flux,该Flux是一组可解析的项目,您可以在其上执行操作:带有回调的flatMap。
然后,使用parallel()方法使其异步。 runOn()用于指示在哪个线程上运行它。 Schedulers.parallel()表示使用的线程数与CPU内核数一样。
sequence()将其恢复为同步状态,以使collectList()再次将所有结果收集到一个列表中。
要等待所有线程完成其业务,请使用block()。结果是带有结果的列表。