我正在使用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秒
为什么会这样?
答案 0 :(得分:10)
HttpHandler 正在I / O线程中执行。如the documentation中所述:
IO线程执行非阻塞任务,永远不应执行阻塞操作,因为它们负责多个连接,因此当操作阻塞时,其他连接将基本挂起。每个CPU核心一个IO线程是合理的默认值。
request lifecycle docs讨论如何将请求分派给工作线程:
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 docs都存在空白,所以我不确定其目的是什么。
答案 1 :(得分:7)
Undertow使用NIO,这意味着单个线程处理所有请求。如果要在请求处理程序中执行阻塞操作,则必须将此操作分派给工作线程。
在您的示例中,您将线程置于休眠状态,这意味着任何请求处理都将处于休眠状态,因为此线程处理所有请求。
但是,即使您将操作分派给工作线程并将其置于睡眠状态,您仍然会看到您提到的阻塞问题。这是因为您在同一浏览器的多个选项卡中打开了相同的URL。浏览器内部阻塞了自己的内容。如果您在不同的标签中打开相同的网址,第二个网址将在第一个网址完成后启动请求。尝试自己想要查看的任何网址。您很容易对此浏览器行为感到困惑。
答案 2 :(得分:4)
最简单的方法是将处理程序包装在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();
}
}