Java 在Mono的阻塞线程上执行转换步骤
有没有办法确保从未来创建的单个Java 在Mono的阻塞线程上执行转换步骤,java,project-reactor,reactive-streams,Java,Project Reactor,Reactive Streams,有没有办法确保从未来创建的单个Mono的所有转换步骤都在订阅和阻塞的线程上执行 例如,下面的代码 publicstaticvoidmain(字符串[]args){ var future=新的CompletableFuture(); var res=Mono.fromFuture(future.map)(val->{ System.out.println(“线程:+Thread.currentThread().getName()); 返回val+“1”; }); 新线程(()->{ 试一试{ 睡眠
Mono
的所有转换步骤都在订阅和阻塞的线程上执行
例如,下面的代码
publicstaticvoidmain(字符串[]args){
var future=新的CompletableFuture();
var res=Mono.fromFuture(future.map)(val->{
System.out.println(“线程:+Thread.currentThread().getName());
返回val+“1”;
});
新线程(()->{
试一试{
睡眠(1000L);
}捕捉(中断异常e){
}
未来。完成(“已完成”);
},“完成符”).start();
res.block();
}
打印
Thread:completer
,因为未来是从“completer”线程完成的。我试图找出是否有办法使其始终打印Thread:main
否。当main
线程通过.block()
被阻塞时,该线程专门等待流的onNext
、onComplete
或onError
信号(在所有上游操作符执行之后)。在调用上游操作符以执行操作符之前,它不会以某种方式重新获得控制
您能做的最接近的事情是确保:
计划程序上执行(通过.subscribeOn
),并且
计划程序上(通过.publishOn
)
Scheduler=Schedulers.parallel();
var res=Mono.fromFuture(未来)
.doFirst(()->{//注意:在3.2.10.RELEASE中添加了doFirst
//在并行调度程序中打印线程(由下面的subscribeOn指定)
System.out.println(“订阅线程:+Thread.currentThread().getName());
})
//指定在其上设置完成值的计划程序
//为下游运营商发布了上述内容
.publishOn(调度程序)
.map(val->{
//在并行调度程序中打印线程(由上面的publishOn指定)
System.out.println(“运算符线程:+Thread.currentThread().getName());
返回val+“1”;
})
//指定订阅上游运算符的计划程序
.subscribeOn(调度程序);
但是,请注意以下几点:
- 订阅发生在
中的线程上,而不是阻塞的调度程序
主线程
- 这种方法只是确保使用相同的
,而不是调度程序
中相同的调度程序
。理论上,您可以通过使用单线程调度程序强制使用相同的线程
线程(例如
)调度程序.newParallel(“单线程”,1)
并不强制所有操作员都在该.publishOn
调度程序上操作。它只会影响下游操作员,直到下一个
,或者直到下一个异步操作员(例如.publishOn
)可能使用不同的.flatMap
调度程序
私有静态类SelfEventLoopExecutor实现Executor{
private final LinkedBlockingQueue=新LinkedBlockingQueue();
@凌驾
public void execute(Runnable命令){
添加的布尔值=queue.add(命令);
添加断言;
}
公共无效排放队列(){
可运行r;
而((r=queue.poll())!=null){
r、 run();
}
}
}
接下来,创建一个订阅服务器,它能够在等待结果的同时使用执行器执行任务,而不是完全阻塞线程
公共静态类LazyBlockingSubscriber实现订阅服务器{
私人最终selfeventloop执行人selfExec;
private volatile boolean completed=false;
T值;
私人易失性可弃性交易所;
公共LazyBlockingSubscriber(SelfEventLoopExecutor selfExec){
this.selfExec=selfExec;
}
@凌驾
认购的公共无效(认购){
s、 请求(1);
}
@凌驾
下一页(T){
值=t;
完成=正确;
}
@凌驾
公共作废登记员(可丢弃的t){
ex=t;
完成=正确;
}
@凌驾
未完成的公共空间(){
完成=正确;
}
公共T块()可丢弃{
而(!已完成){
selfExec.drainQueue();
}
如果(ex!=null){
掷骰子;
}
返回值;
}
}
现在,我们可以用以下方式修改代码
publicstaticvoidmain(String[]args)抛出Throwable{
var future=新的CompletableFuture();
var selfExec=new SelfEventLoopExecutor();//我们的新执行器
var res=Mono.fromFuture(未来)
.publishOn(Schedulers.fromExecutor(selfExec))//在新的执行器上进行调度
.map(val->{
System.out.println(“线程:+Thread.currentThread().getName());
返回val+“1”;
});
新线程(()->{
试一试{
睡眠(1000L);
}捕捉(中断异常e){
}
未来。完成(“已完成”);
},“完成符”).start();
var subs=newlazyblockingsubscriber(selfExec);//惰性订阅
res.Th(subs);
block();//旋转等待
}
因此,代码将打印Thread:main