2011-09-02 107 views
12

我想知道Tomcat 7如何實現異步處理。我知道請求線程立即返回,允許請求線程立即偵聽新請求並對其進行響應。Tomcat 7異步處理

如何處理'異步'請求?是否有獨立的線程池來處理異步請求?我認爲阻塞IO處理使用類似java.nio.Selector的性能。 CPU計算阻塞的線程怎麼樣?

+0

你可能想看看這個:http://stackoverflow.com/questions/ 7749350/illegalstateexception-not-supported-on-asynccontext-startasyncreq-res如果你想在Tomcat 7上實現異步處理。有一個轉折點。 – JVerstry

回答

37

你在混淆不同的概念。您必須區分:

  1. 按照Servlet 3.0的異步請求處理;一個API,使您能夠從Web容器線程池中分離傳入的Servlet請求。它不會即時創建任何線程。接口的用戶需要實施適當的多線程解決方案。它不涉及非阻塞IO。
  2. 線程池;提供了一種機制來獲取和管理Web容器中的線程。當談到異步請求處理你有2個選項。您可以定義自己的ExecutorService並使用它來進一步處理請求,或者可以創建新的Runnable,並通過調用AsyncContext.start()將其提交到獲得的AsyncContext。對於Tomcat,後一種方法使用在server.xml中定義的Tomcat線程池。
  3. 非阻塞IO(NIO);雖然它是異步以及它是一個不同的故事。它涉及非阻塞IO操作,如磁盤或網絡IO。如果你想啓用NIO進行HTTP請求處理,看看Tomcat的documentation

下面的例子概括了它可以如何工作。它只對工作者作業使用一個線程。如果你在並行2個​​不同的瀏覽器的輸出看起來像這樣運行它(我使用自定義記錄器):

DATE       THREAD_ID LEVEL  MESSAGE 
2011-09-03 11:51:22.198 +0200  26  I:  >doGet: chrome 
2011-09-03 11:51:22.204 +0200  26  I:  <doGet: chrome 
2011-09-03 11:51:22.204 +0200  28  I:  >run: chrome 
2011-09-03 11:51:27.908 +0200  29  I:  >doGet: firefox 
2011-09-03 11:51:27.908 +0200  29  I:  <doGet: firefox 
2011-09-03 11:51:32.227 +0200  28  I:  <run: chrome 
2011-09-03 11:51:32.228 +0200  28  I:  >run: firefox 
2011-09-03 11:51:42.244 +0200  28  I:  <run: firefox 

你看到doGet方法立即完成,而工人仍然運行。 2個測試請求:http://localhost:8080/pc/TestServlet?name=chromehttp://localhost:8080/pc/TestServlet?name=firefox

簡單的例子Servlet的

@WebServlet(asyncSupported = true, value = "/TestServlet", loadOnStartup = 1) 
public class TestServlet extends HttpServlet { 
    private static final Logger LOG = Logger.getLogger(TestServlet.class.getName()); 
    private static final long serialVersionUID = 1L; 
    private static final int NUM_WORKER_THREADS = 1; 

    private ExecutorService executor = null; 

    @Override 
    public void init() throws ServletException { 
     this.executor = Executors.newFixedThreadPool(NUM_WORKER_THREADS); 
    } 

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 

     final String name = request.getParameter("name"); 
     LOG.info(">doGet: " + name); 

     AsyncContext ac = request.startAsync(); // obtain async context 
     ac.setTimeout(0); // test only, no timeout 

     /* Create a worker */ 
     Runnable worker = new TestWorker(name, ac); 

     /* use your own executor service to execute a worker thread (TestWorker) */ 
     this.executorService.execute(worker); 

     /* OR delegate to the container */ 
     // ac.start(worker); 

     LOG.info("<doGet: " + name); 
    } 
} 

......和TestWorker

public class TestWorker implements Runnable { 
    private static final Logger LOG = Logger.getLogger(TestWorker.class.getName()); 
    private final String name; 
    private final AsyncContext context; 
    private final Date queued; 

    public TestWorker(String name, AsyncContext context) { 
     this.name = name; 
     this.context = context; 
     this.queued = new Date(System.currentTimeMillis()); 
    } 

    @Override 
    public void run() { 

     LOG.info(">run: " + name); 

     /* do some work for 10 sec */ 
     for (int i = 0; i < 100; i++) { 
      try { 
       Thread.sleep(100); 
      } catch (InterruptedException e) { 
       throw new RuntimeException(e); 
      } 
     } 

     ServletResponse response = this.context.getResponse(); 
     response.setContentType("text/plain"); 

     try { 
      PrintWriter out = response.getWriter(); 
      out.println("Name:\t\t" + this.name); 
      out.println("Queued:\t\t" + this.queued); 
      out.println("End:\t\t" + new Date(System.currentTimeMillis())); 
      out.println("Thread:\t\t" + Thread.currentThread().getId()); 
      out.flush(); 
     } catch (IOException e) { 
      throw new RuntimeException(e); 
     } 

     this.context.complete(); 

     LOG.info("<run: " + name); 
    } 
} 
+0

感謝您的澄清。關於CometProcessor API,是否有一個線程輪詢所有當前連接以查看哪一個具有「可供讀取的數據」?具體而言,當有10個請求與100個請求時,線程的預期數量是多少?假設這些請求已收到BEGIN事件,但尚未收到READ事件。 http://tomcat.apache.org/tomcat-7.0-doc/aio.html –

+0

@John如果你對家的答案感到滿意,你應該批准它。你應該提出一個新的問題(最終,你可以參考這個問題)。 – JVerstry

+0

HI @JVerstry,說實話,我並不完全滿意答案。對於「異步處理」,我仍然不認爲我對Tomcat的體系結構有很好的理解。 –