2014-02-28 147 views
10

我正在使用Undertow创建一个简单的应用程序。Undertow如何做非阻塞IO?

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秒

为什么是这样吗?

回答

9

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都有差距,所以我不确定它的目的是什么。

+0

好的。谢谢你:) – eclipse

+0

@McDowell Node.js与异步通信有何不同? – johnny

4

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

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

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

3

最简单的事情就是把你的处理程序包装在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(); 
    } 
}