12

我正在使用 Undertow 创建一个简单的应用程序。

public class App {
    public static void main(String[] args) {
        Undertow server = Undertow.builder().addListener(8080, "localhost")
                .setHandler(new HttpHandler() {

                    public void handleRequest(HttpServerExchange exchange) throws Exception {
                        Thread.sleep(5000);
                        exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/plain");
                        exchange.getResponseSender().send("Hello World");
                    }

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

我打开了一个浏览器选项卡localhost:8080,我也打开了第二个选项卡localhost:8080

这次第一个选项卡将等待 5 秒,第二个选项卡将等待 10 秒

为什么会这样?

4

3 回答 3

13

HttpHandler在 I/O 线程中执行文档中所述

IO线程执行非阻塞任务,并且不应该执行阻塞操作,因为它们负责多个连接,所以当操作阻塞时,其他连接基本上会挂起。每个 CPU 内核一个 IO 线程是合理的默认值。

请求生命周期文档讨论了如何将请求分派到工作线程:

import io.undertow.Undertow;
import io.undertow.server.*;
import io.undertow.util.Headers;

public class Under {
  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();
  }
}

我注意到每个请求不一定会获得一个工作线程 - 当我在标头上设置断点时,我会为每个客户端获得大约一个线程。Undertow 和底层XNIO 文档都存在差距,所以我不确定意图是什么。

于 2014-02-28T12:34:17.623 回答
8

Undertow 使用 NIO,这意味着单个线程处理所有请求。如果要在请求处理程序中执行阻塞操作,则必须将此操作分派给工作线程。

在您的示例中,您使线程进入睡眠状态,这意味着任何请求处理都被置于睡眠状态,因为该线程处理所有请求。

但是,即使您将操作分派给工作线程并将其置于睡眠状态,您仍然会看到您提到的阻塞问题。这是因为您在同一浏览器的多个选项卡中打开了相同的 url。浏览器有自己的内部阻塞。如果您在不同的选项卡中打开相同的 url,第二个 url 将在第一个完成后开始请求。尝试您想亲自查看的任何网址。您很容易与这种浏览器行为混淆。

于 2015-12-05T21:11:09.497 回答
8

最简单的做法是将处理程序包装在 BlockingHandler 中。

import io.undertow.Undertow;
import io.undertow.server.*;
import io.undertow.server.handlers.BlockingHandler;
import io.undertow.util.Headers;

public class Under {
    public static void main(String[] args) {
        Undertow server = Undertow.builder()
                .addHttpListener(8080, "localhost")
                .setHandler(new BlockingHandler(new HttpHandler() {
                    public void handleRequest(HttpServerExchange exchange)
                            throws Exception {
                        exchange.getResponseHeaders()
                                .put(Headers.CONTENT_TYPE, "text/plain");
                        exchange.getResponseSender()
                                .send("Hello World");
                    }
                })).build();
        server.start();
    }
}
于 2016-05-02T19:12:53.157 回答