如何在Undertow的非阻塞处理程序中执行阻塞代码?

时间:2019-07-05 13:18:26

标签: java asynchronous undertow

separate question中所述,在使用Undertow时,所有处理都应在专用的Worker线程池中完成,如下所示:

public class Start {

  public static void main(String[] args) {
    Undertow server = Undertow.builder()
        .addListener(8080, "localhost")
        .setHandler(new HttpHandler() {
          public void handleRequest(HttpServerExchange exchange)
              throws Exception {
            if (exchange.isInIoThread()) {
              exchange.dispatch(this);
              return;
            }
            exchange.getResponseHeaders()
                    .put(Headers.CONTENT_TYPE, "text/plain");
            exchange.getResponseSender()
                    .send("Hello World");
          }
        })
        .build();
    server.start();
  }
}

我知道BlockingHandler可用于明确告诉Undertow将请求安排在专用线程池上以阻止请求。我们可以通过将HttpHandler包装在BlockingHandler的实例中来适应上面的示例,如下所示:

        .setHandler(new BlockingHandler(new HttpHandler() {

这将适用于我们一直阻塞的呼叫。

但是,如果某些代码在大多数时间是非阻塞的,但有时需要阻塞调用,那么如何将那个阻塞调用变成非阻塞代码呢?例如,如果请求的值存在于缓存中,则以下代码将不会阻塞(它只是从某些Map<>中获取),但是如果没有,则必须从数据库中获取它。

public class Start {

  public static void main(String[] args) {
    Undertow server = Undertow.builder()
        .addListener(8080, "localhost")
        .setHandler(new HttpHandler() {
          public void handleRequest(HttpServerExchange exchange)
              throws Exception {
            if (exchange.isInIoThread()) {
              exchange.dispatch(this);
              return;
            }
            if (valueIsPresentInCache(exchange)) {
              return valueFromCache;  // non-blocking
            } else {
              return fetchValueFromDatabase(); // blocking!!!
            }
          }
        })
        .build();
    server.start();
  }
}

根据docs,有一种方法HttpServerExchange.startBlocking(),但是根据JavaDoc的说法,除非您确实需要使用输入流,否则此调用仍然是阻塞的。

  

调用此方法会将交换置于阻止模式,并创建一个   BlockingHttpExchange对象存储流。当交换是   在阻塞模式下,输入流方法变得可用,除了   目前,阻止   非阻塞模式

一个人如何将这种阻塞性呼叫变成非阻塞性呼叫?

1 个答案:

答案 0 :(得分:0)

正确的方法是实际上在IO线程中执行逻辑(如果它是非阻塞的)。否则,将请求委托给专用线程,例如:

public class Example {

  public static void main(String[] args) {
    Undertow server = Undertow.builder()
        .addListener(8080, "localhost")
        .setHandler(new HttpHandler() {
          public void handleRequest(HttpServerExchange exchange)
              throws Exception {

            if (valueIsPresentInCache(exchange)) {
              getValueFromCache();  // non-blocking, can be done from IO thread           
            } else {

              if (exchange.isInIoThread()) {
                exchange.dispatch(this);
                // we return immediately, otherwise this request will be
                // handled both in IO thread and a Worker thread, throwing
                // an exception
                return;
              }

              fetchValueFromDatabase(); // blocking!!!

            }
          }
        })
        .build();
    server.start();
  }
}