Concurrency Java 8,然后是apply()和accept()
我正在为链接Concurrency Java 8,然后是apply()和accept(),concurrency,java-8,Concurrency,Java 8,我正在为链接completablefuture操作创建一个演示示例,我想我已经接近了,但我缺少了一些东西。除了main()中的最后一个“Build cakes in parallel”子句外,所有内容都可以编译: import java.util.*; 导入java.util.concurrent.*; 导入java.util.function.*; 导入java.util.stream.*; 导入java.time.*; //使用装饰图案构建蛋糕: 接口蛋糕{ 字符串descripe(); }
completablefuture
操作创建一个演示示例,我想我已经接近了,但我缺少了一些东西。除了main()
中的最后一个“Build cakes in parallel”子句外,所有内容都可以编译:
import java.util.*;
导入java.util.concurrent.*;
导入java.util.function.*;
导入java.util.stream.*;
导入java.time.*;
//使用装饰图案构建蛋糕:
接口蛋糕{
字符串descripe();
}
类蛋糕工具蛋糕{
私有int-id;
公共蛋糕(int-id){this.id=id;}
@凌驾
公共字符串descripe(){
返回“蛋糕”+id;
}
}
抽象类装饰器实现Cake_{
保护蛋糕;
公共装饰师(蛋糕){
这个蛋糕=蛋糕;
}
@凌驾
公共字符串descripe(){
返回蛋糕。描述();
}
@凌驾
公共字符串toString(){
返回descripe();
}
}
类磨砂扩展装饰器{
公共糖霜(蛋糕){
超级(蛋糕);
}
@凌驾
公共字符串descripe(){
返回蛋糕。描述()+“磨砂”;
}
}
类装饰器{
公共装饰(蛋糕){
超级(蛋糕);
}
@凌驾
公共字符串descripe(){
返回蛋糕。descripe()+“装饰”;
}
}
//对于蛋糕制造装配线:
类CreateSupplier{
私有int-id;
公共创建蛋糕(int-id){
this.id=id;
}
@凌驾
公共蛋糕{
返回新蛋糕(id);
}
}
类实现函数{
@凌驾
公共霜敷(蛋糕){
返回新的磨砂(蛋糕);
}
}
类decorecakes实现消费者{
公开结果;
@凌驾
公共无效接受(霜状fc){
结果=新装饰(fc);
}
}
公开课考试{
公共静态int NUM OF_=20;
公共静态void main(字符串[]args){
//更改默认的线程数:
System.setProperty(
“java.util.concurrent.ForkJoinPool”+
“.common.parallelism”、“+NUM_OF_饼”;
//测试/演示装饰图案:
装饰清单=
IntStream.range(0,蛋糕的数量)
.mapToObj(蛋糕::新)
.map(磨砂::新建)
.map(装饰::新建)
.collect(Collectors.toList());
forEach(System.out::println);
//并行构建蛋糕:
列表对您的问题的快速回答是,thenApply
行没有编译,因为上面这行(map(CompletableFuture::supplyAsync)
)的结果返回Stream
,而不是CompletableFuture
。
您需要执行类似于map(cakeFuture->cakeFuture.thenappy(new FrostCakes())
的操作
但我认为还有更重要的一点需要说明
如果您的示例是出于教育目的,我建议您再花一两天时间准备,更具体地说,是阅读流操作的基础知识和CompletableFuture
这样,当你开始展示你的材料时,你会感到更加自信,但更重要的是,你不会展示不完美的代码示例,这可能会损害你的同事/学生关于如何使用流和CompletableFuture
s(甚至decorators)的概念
我会在你们的例子中指出一些我认为需要重做的事情
手动设置公共ForkJoinPool
的并行级别并不总是一个好主意。默认情况下,它使用运行时返回的处理器数量。availableProcessors()
这是一个非常好的默认值。您需要有一个非常好的理由将其更改为其他值,因为在大多数情况下,您只会从调度和维护冗余线程中引入不必要的开销。而将其更改为您计划启动的任务数几乎总是一个坏主意(解释省略)
forEach
,可以说这将是一个更好的演示使用Java8流对fluent编程模型进行优化IntStream.range()之后添加.parallel()
来轻松解决此问题
,但除非您从上面删除要列出的冗余集合,否则仅通过使用forEach
打印列表内容,您将无法看到您已经并行完成了一些操作java.util.function
接口的类不是很惯用。我认为应该用相应的lambda表达式替换它们,即使在您的例子中,这可能会导致lambda中出现大量lambda,除非第二个示例稍微重写CompletableFuture。然后accept
返回一个CompletableFuture
,因此在流处理的这一阶段,您会丢失对已创建、磨砂和装饰蛋糕的引用。如果您不关心它们,或者如果您在装饰逻辑中记录了一些关于它们的信息,这是可以的,但您的示例很容易误导人们最后收集的CompletableFuture
s列表可以用来获取蛋糕(毕竟,谁不想既有蛋糕又吃蛋糕)IntStream.range(0, NUM_OF_CAKES)
.parallel()
.mapToObj(Cake::new)
.map(Frosted::new)
.map(Decorated::new)
.forEach(System.out::println);
请注意,由于并行执行,蛋糕ID没有排序。当询问编译错误时,请发布编译错误。您正在对流调用thenApply()。流没有任何thenApply()方法。
IntStream.range(0, NUM_OF_CAKES)
.parallel()
.mapToObj(Cake::new)
.map(Frosted::new)
.map(Decorated::new)
.forEach(System.out::println);