Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/visual-studio-2012/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在Mono的阻塞线程上执行转换步骤_Java_Project Reactor_Reactive Streams - Fatal编程技术网

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