我正在学习反应堆核心,并遵循此https://www.baeldung.com/reactor-core
ArrayList<Integer> arrList = new ArrayList<Integer>();
System.out.println("Before: " + arrList);
Flux.just(1, 2, 3, 4)
.log()
.map(i -> i * 2)
.subscribeOn(Schedulers.parallel())
.subscribe(arrList::add);
System.out.println("After: " + arrList);
当我执行上面的代码行时,给出提示。
Before: []
[DEBUG] (main) Using Console logging
After: []
以上代码行应在另一个线程中开始执行,但根本无法正常工作。 有人可以帮我吗?
答案 0 :(得分:2)
我认为有些混乱。当您致电Foo
时。您指定要在其他线程上接收项目。另外,您还必须减慢代码速度,以便实际启动订阅cen(这就是为什么我添加了Bar
)。如果您运行我已通过的代码,它将起作用。您会看到反应堆中没有魔术同步机制。
subscribeOn(Schedulers.parallel())
如果要在并行反应器中将项目添加到列表中,不是一个好的选择。最好在Java 8中使用并行流。
Thread.sleep(100)
关于并发部分,您发布的教程并不十分精确。值得称赞的是,他/她说还将发表更多文章。但是我不认为应该发布该特定示例,因为它会造成混乱。我建议不要太信任互联网上的资源:)
答案 1 :(得分:0)
如Reactor文档中针对各种subscribe
方法所述:
请记住,由于序列可以是异步的,因此这将 立即将控制权返回给调用线程。这可以给 印象在主线程中执行时未调用使用者 或例如单元测试。
这意味着到达main方法的末尾,因此主线程在任何线程能够订阅Reactive链之前退出,如Piotr所述。
您要做的是等到整个链完成后再打印阵列的内容。
天真的做法是:
ArrayList<Integer> arrList = new ArrayList<>();
System.out.println("Before: " + arrList);
Flux.just(1, 2, 3, 4)
.log()
.map(i -> i * 2)
.subscribeOn(Schedulers.parallel())
.doOnNext(arrList::add)
.blockLast();
System.out.println("After: " + arrList);
在这里,您阻塞主线程上的执行,直到处理Flux上的最后一个元素为止。因此,在完全填充ArrayList之前,不会执行最后一个System.out。
请记住,代码在控制台应用程序和Netty等服务器环境中运行的方式有些不同。使控制台应用程序等待所有订阅加入的唯一方法是block
。
但是在并行线程上不允许阻塞。因此,这种方法在Netty环境中行不通。您的服务器将在那里运行,直到显式关闭为止,因此subscribe
就可以了。
但是,在上面的代码段中,您要阻止的不仅是防止应用程序退出,还是在读取已填充的数据之前等待。
对上述代码的改进如下:
ArrayList<Integer> arrList = new ArrayList<>();
System.out.println("Before: " + arrList);
Flux.just(1, 2, 3, 4)
.log()
.map(i -> i * 2)
.subscribeOn(Schedulers.parallel())
.doOnNext(arrList::add)
.doOnComplete(() -> System.out.println("After: " + arrList))
.blockLast();
即使在这里,doOnComplete
也会从反应链外部访问数据。为了避免这种情况,您可以像这样在链中收集助焊剂的元素,如下所示:
System.out.println("Before.");
Flux.just(1, 2, 3, 4)
.log()
.map(i -> i * 2)
.subscribeOn(Schedulers.parallel())
.collectList()
.doOnSuccess(list -> System.out.println("After: " + list))
.block();
同样,请记住,在Netty中运行时(例如Spring Webflux应用程序),以上代码将以subscribe()
结尾。
但是请注意,从Flux到List(或任何Collection)的切换意味着您正在从反应式范式切换到命令式编程。您应该能够在Reactive范本本身内实现任何功能。