Java 是否可以在不使用ProjectReactor阻塞线程的情况下等待事件?
Project Reactor是否可以在mono中等待事件/条件,而无需为每个mono使用阻塞线程?有了Java 是否可以在不使用ProjectReactor阻塞线程的情况下等待事件?,java,multithreading,project-reactor,Java,Multithreading,Project Reactor,Project Reactor是否可以在mono中等待事件/条件,而无需为每个mono使用阻塞线程?有了CompletableFuture我可以完成这样的事情,但我不知道如何使用projectreactor来完成 我的问题是,我需要将请求与响应关联起来。响应时间变化很大,有些甚至永远不会得到回复和超时。在客户端,每个请求阻塞一个线程不是问题,但由于这是一个服务器应用程序,我不希望每个请求生成一个线程来阻塞等待响应 API的外观如下所示: Mono-doRequest(Mono请求); 由于我不
CompletableFuture
我可以完成这样的事情,但我不知道如何使用projectreactor来完成
我的问题是,我需要将请求与响应关联起来。响应时间变化很大,有些甚至永远不会得到回复和超时。在客户端,每个请求阻塞一个线程不是问题,但由于这是一个服务器应用程序,我不希望每个请求生成一个线程来阻塞等待响应
API的外观如下所示:
Mono-doRequest(Mono请求);
由于我不知道如何使用反应堆,我将解释如何使用CompletableFuture
来澄清我在寻找什么。API如下所示:
CompletableFuture-doRequest(请求);
调用方调用时,会向服务器发出请求,其中包含由该方法生成的相关ID。调用方将返回一个CompletableFuture
,该方法将对该CompletableFuture
的引用存储在map中,相关ID作为键
还有一个线程(池),用于接收服务器的所有响应。当它收到响应时,它从响应中获取相关ID,并使用它在映射中查找原始请求(即CompletableFuture
),并调用complete(响应)代码>在上面
在这个实现中,每个请求不需要阻塞线程。这基本上更像是一种Vert.X/Netty的思维方式?我想知道如何用ProjectReactor实现这样的事情(如果可能的话)
编辑日期:2019年7月25日:
根据评论中的要求,下面是我将如何使用completablefuture
实现这一点的示例,以澄清我的想法
我还注意到我犯了一个可能会让人困惑的错误:在CompletableFuture
示例中,我传递了一个Mono
作为参数。这应该只是一个“正常”的论点。我很抱歉,我希望我没有让人们太困惑
import java.util.concurrent.CompletableFuture;
导入java.util.concurrent.ConcurrentHashMap;
类NonBlockingCorrelationExample{
/**
*此示例演示如何在不需要(睡眠)的情况下实现请求与响应的关联
*使用{@link CompletableFuture}对每个请求执行线程以等待响应。
*
*因此,本例的主要特点是,始终使用固定(少量)的线程,即使只有一个线程
*会发出数千个请求。
*/
公共静态void main(字符串[]args)引发异常{
RequestResponseService RequestResponseService=新的RequestResponseService();
请求=新请求();
request.correlationId=1;
request.question=“你会说西班牙语吗?”;
CompletableFuture-responseFuture=requestResponseService.doRequest(请求);
responseFuture.whenComplete((response,throwable)->System.out.println(response.answer));
//这里的阻塞调用只是为了在演示完成之前应用程序不会退出。
responseFuture.get();
}
静态类RequestResponseService{
/**此映射中的键是相关ID*/
私有最终ConcurrentHashMap响应=新ConcurrentHashMap();
CompletableFuture-doRequest(请求){
响应=新响应();
response.correlationId=request.correlationId;
CompletableFuture-ResponseFuture=新的CompletableFuture();
responses.put(response.correlationId,reponseFuture);
doNonBlockingFireAndForgetRequest(请求);
回报未来;
}
私有void doNonBlockingFireAndForgetRequest(请求){
//在我的例子中,请求将在请求主题中的MQTT代理(消息总线)上发布。
//现在我们只需要打一个电话,模拟一段时间后收到的响应消息。
模拟器响应();
}
私有void processResponse(响应){
//通常会有一个(小)线程池,它订阅了接收消息的消息总线
//并调用此方法来处理这些消息。
CompletableFuture-responseFuture=responses.get(response.correlationId);
响应未来。完成(响应);
}
void模拟器响应(){
//这只是为了让示例发挥作用,而不是示例的一部分。
新线程(()->{
试一试{
//模拟延迟。
睡眠(10_000);
响应=新响应();
response.correlationId=1;
response.answer=“Si!”;
过程响应(response);
}捕捉(中断异常e){
e、 printStackTrace();
}
}).start();
}
}
静态类请求{
长相关ID;
字符串问题;
}
静态类响应{
长相关ID;
字符串回答;
}
}
是的,这是可能的。您可以使用reactor.core.publisher.Mono#create
方法来实现它
例如:
public static void main(String[] args) throws Exception {
RequestResponseService requestResponseService = new RequestResponseService();
Request request = new Request();
request.correlationId = 1;
request.question = "Do you speak Spanish?";
Mono<Request> requestMono = Mono.just(request)
.doOnNext(rq -> System.out.println(rq.question));
requestResponseService.doRequest(requestMono)
.doOnNext(response -> System.out.println(response.answer))
// The blocking call here is just so the application doesn't exit until the demo is completed.
.block();
}
static class RequestResponseService {
private final ConcurrentHashMap<Long, Consumer<Response>> responses =
new ConcurrentHashMap<>();
Mono<Response> doRequest(Mono<Request> request) {
return request.flatMap(rq -> doNonBlockingFireAndForgetRequest(rq)
.then(Mono.create(sink -> responses.put(rq.correlationId, sink::success))));
}
private Mono<Void> doNonBlockingFireAndForgetRequest(Request request) {
return Mono.fromRunnable(this::simulateResponses);
}
private void processResponse(Response response) {
responses.get(response.correlationId).accept(response);
}
void simulateResponses() {
// This is just to make the example work. Not part of the example.
new Thread(() -> {
try {
// Simulate a delay.
Thread.sleep(10_000);
Response response = new Response();
response.correlationId = 1;
response.answer = "Si!";
processResponse(response);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
publicstaticvoidmain(字符串[]args)引发异常{
RequestResponseService RequestResponseService=新的RequestResponseService();
请求=新请求();
request.correlationId=1;
request.question=“你会说西班牙语吗?”;
Mono requestMono=Mono.just(请求)