2014-02-28 88 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(); 
    } 
}