为了账号安全,请及时绑定邮箱和手机立即绑定

Vertx HTTPClient 与 CompletableFuture 阻塞回调线程

Vertx HTTPClient 与 CompletableFuture 阻塞回调线程

慕田峪7331174 2021-10-28 15:51:00
我正面临一个非常奇怪的问题。我正在使用 Vert.x 和处理程序,我正在使用 Vert.x 调用 REST API HttpClientRequest。现在我有一个CompletableFuture我正在HttpClientRequest. 后来,我使用CompletableFuture.get(). 但是无论何时get()调用方法,主线程都会被阻塞(正如预期的那样),但它会永远被阻塞。我没有看到回调发生在我的响应处理程序上并且它永远被卡住了。这是代码:import io.vertx.core.http.HttpClientRequest;import io.vertx.core.http.HttpMethod;import io.vertx.core.json.Json;import io.vertx.core.json.JsonObject;import java.util.concurrent.CompletableFuture;import io.vertx.core.http.HttpClient;CompletableFuture<JsonObject> comp = new CompletableFuture<JsonObject>();   HttpClient httpClient = new HttpClient(); //This object initialized and set the endpoit, port and domain name.HttpClientRequest request = httpClient.request(HttpMethod.POST, requestURI, response -> {        response.bodyHandler(body -> {            //do some process            comp.complete(new JsonObject(body);        });    }).exceptionHandler(e -> {        //log the error        comp.completeExceptionally(e);    });request.end();//after some processcomp.get();  // here main thread is stuck forever.我的 API 给出了 200 个响应,我在 Wireshark 中看到了,如果我执行comp.thenAccept()回调,它会给出我的结果。为什么会发生这种情况,解决方案是什么?
查看完整描述

2 回答

?
湖上湖

TA贡献2003条经验 获得超2个赞

您的实现的问题在于它违反了黄金法则 - 不要阻止事件循环。您不应该像CompletableFuture.get()在事件循环中那样调用阻塞操作。同样,sampleHandler()也不应该调用Thread.sleep()事件循环,但这是一个较小的问题。


结果是你的事件循环现在被阻塞了……所以你的/sample请求不能再被处理了。并且由于请求没有被处理,你CompletableFuture仍然没有完成……死锁。


这个问题有两种可能的解决方案:


CompletableFuture按设计使用,依赖于链式调用而不是get(),尽管它不强制执行 Vert.x 的线程模型。例如:


comp.whenComplete((result, e) -> {

    System.out.println("Got sample response");

    if (e != null) {

        context.response().setStatusCode(500)

                .end(e.getMessage());

    } else {

        context.response().setStatusCode(200)

                .putHeader("content-type", "text/html")

                .end(result);

    }

    System.out.println("end testCompBlocking....");

});

使用 Vert.x 工具运行阻塞代码。这应该不是必需的,CompletableFuture但其他 API 可能需要它。例如:


context.vertx().<String>executeBlocking(future -> {

            String result = "Not Success";

            try {

                result = comp.get();

            } catch (Exception e) {

                System.out.println("Exception in getting from Completable..." + e.getMessage());

                e.printStackTrace();

            }

            future.complete(result);

        },

        false,

        result -> {

            context.response().setStatusCode(200);

            context.response().putHeader("content-type", "text/html");

            context.response().end(result.result());

            System.out.println("end testCompBlocking....");

        });


查看完整回答
反对 回复 2021-10-28
?
拉丁的传说

TA贡献1789条经验 获得超8个赞

get() 阻塞主线程直到未来完成,但是,HttpClientRequest 在主线程上执行,因此这种情况会导致死锁。

相反,它thenAccept()是非阻塞的,仅创建一个在未来完成时执行的回调。


根据您提供的代码,您的用例不清楚;您是否有理由分别使用HttpClientandCompletableFuture而不是WebClientand Future

如果您需要使用 CompletableFuture,那么您应该查看项目以获得与 Vert.x 更兼容的实现。


查看完整回答
反对 回复 2021-10-28
  • 2 回答
  • 0 关注
  • 586 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信