如何做非阻塞IO?

时间:2014-02-28 10:12:15

标签: java undertow

我正在使用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秒

为什么会这样?

3 个答案:

答案 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();
    }
}