2011-09-02 22 views
12

Tomcat 7で非同期処理がどのように実装されているのでしょうか。私は、リクエストスレッドが即座に戻り、リクエストスレッドが直ちに新しいリクエストを待ち受けて応答できることを理解しています。Tomcat 7非同期処理

'async'リクエストはどのように処理されますか?非同期要求を処理する別のスレッドプールがありますか?私は、ブロックIOはパフォーマンスのためにjava.nio.Selectorのようなものを使用して処理されると仮定します。 CPUの計算でブロックされているスレッドはどうですか?

+0

あなたはこのを見てみたいことがあります。http://stackoverflow.com/questions/ 7749350/Tomcat 7で非同期処理を実装したい場合は、asynccontext-startasyncreq-resume-not-supported-on-asynccontextを使用してください。 – JVerstry

答えて

37

異なる概念を混在させています。あなたは区別する必要があります。

  1. サーブレット3.0あたりとして非同期リクエストの受け渡しを、受信したサーブレットリクエストをWebコンテナのスレッドプールから切り離すことを可能にするAPI。その場でスレッドを作成するわけではありません。インターフェイスのユーザーは、適切なマルチスレッドソリューションを実装する必要があります。ノンブロッキングIOには関係しません。
  2. スレッドプール; Webコンテナ内のスレッドを取得および管理するためのメカニズムを提供します。 非同期要求ハンドブックには2つのオプションがあります。独自のExecutorServiceを定義してリクエストを処理したり、Runnableを新たに作成してAsyncContextに送信したりすることができます(AsyncContext.start())。 Tomcatの場合、後者の方法では、server.xmlで定義されているTomcatのスレッドプールを使用します。
  3. ノンブロッキングIO(NIO); でも非同期ですが、それは別の話です。ディスクまたはネットワークIOのようなノンブロッキングIO操作に関連しています。 HTTPリクエスト処理にNIOを有効にする場合は、Tomcatのdocumentationを見てください。ザ・例以下

は、どのようにそれができる作業の概要を説明します。これは、ワーカー・ジョブに対して1つのスレッドのみを使用します。あなたは労働者がまだ実行され、一方、doGet方法は、直ちに、終了していることがわかり

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 

:あなたは、出力は次のようになり並列に2つの異なるブラウザからそれを実行する場合(私はカスタムロガーを使用します)。 2つのテストリクエスト:http://localhost:8080/pc/TestServlet?name=chromehttp://localhost:8080/pc/TestServlet?name=firefox

簡単な例サーブレット

@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

@ジョンあなたが家の答えに満足している場合は、それを承認する必要があります。追加の質問は新しい質問にする必要があります(最終的には、これを参照することができます)。 – JVerstry

+0

HI @JVststry、正直言って私は答えに完全に満足しているとは思わない。私はまだ "非同期処理"のためにTomcatのアーキテクチャをよく理解しているような気がしません。 –

関連する問題