2014-03-04 163 views
3

我有一個接受請求並寫入長響應的servlet。響應處於使用Thread.sleep(1000)模擬長時間運行操作的循環中。我試圖在這裏設置一個異步請求,如代碼所示。但它不起作用。當我向servlet調用多個請求時,它們都是連續執行的,而不是同時執行。我究竟做錯了什麼?異步servlet不能異步執行

而我通過servlet應該是線程 - 每個請求到服務器導致容器執行一個新的線程(或從池中重用一個)。

package test; 

import java.io.IOException; 
import java.io.PrintWriter; 
import javax.servlet.ServletException; 

import javax.servlet.http.HttpServlet; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 

import javax.servlet.AsyncContext; 

import javax.servlet.annotation.WebServlet; 

@WebServlet(urlPatterns={"/test"}, asyncSupported=true) 
public class TestServ extends HttpServlet { 

    @Override 
    public void doGet(HttpServletRequest rq, HttpServletResponse rs){ 

     rs.setContentType("text/plain"); 
     rs.setHeader("Access-Control-Allow-Origin", "*"); 


     AsyncContext asy = rq.startAsync(rq, rs); 
     asy.start(new Client(asy)); 
    } 


    @Override 
    public String getServletInfo() { 
     return "Short description"; 
    } 
} 

class Client implements Runnable { 

    private int counter = 0; 
    private AsyncContext asy; 

    Client(AsyncContext asy) { 
     this.asy = asy; 
    } 

    @Override 
    public void run() { 
     //run long task here 
     try { 
      PrintWriter out = asy.getResponse().getWriter(); 
      while (counter < 5) { 

       out.println(counter++ + 1); 
       Thread.sleep(1000); 

      } 

     } catch (Exception ex) { 

     } finally{ 
      asy.complete(); 
     } 
    } 
} 
+1

您是如何設定servlet容器的線程池? – vanza

+0

你如何生成請求到您的Servlet? –

+0

Mark,XMLHttpRequest - 「get」。 – user3348039

回答

1

使用方法ExecutorService.execute()產卵在後臺線程一些任務。

執行步驟:

  • 閱讀來自web.xml中在servlet初始化一些初始化參數()方法,諸如超時而threadpoolsize
    • 超時參數用於設定異步線程的超時
    • threadpoolsize用於通過調用HTTP request.startAsync()中的doGet()或doPost(以創建異步線程
  • 獲取AsyncContext池)實現方法具AsyncContext
  • 連接監聽器,這個AsyncContext的生命週期事件,如的onComplete(),onTimeout(),onerror的(),onStartAsync()
  • 呼叫ExecutorService.execute(迴應)d
  • 超時設置爲產卵一些任務在後臺線程

試試這個示例代碼。它可能會幫助你。

AsyncServletTaskProcessor:

import java.io.IOException; 

import javax.servlet.AsyncContext; 
import javax.servlet.ServletException; 

public interface AsyncServletTaskProcessor { 

    void process(AsyncContext ctx) throws IOException, ServletException; 
} 

TestServ:

import java.io.IOException; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 

import javax.servlet.AsyncContext; 
import javax.servlet.ServletException; 
import javax.servlet.annotation.WebServlet; 
import javax.servlet.http.HttpServlet; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 

@WebServlet(urlPatterns = { "/test" }, asyncSupported = true) 
public class TestServ extends HttpServlet implements AsyncServletTaskProcessor{ 

    /** The exec. */ 
    private ExecutorService exec; 

    public int CALLBACK_TIMEOUT; 

    public void init() throws ServletException { 
     // read callback timeout form web.xml as init parameter 
     CALLBACK_TIMEOUT = Integer.parseInt(getInitParameter("timeout")); 
     // read thread pool size form web.xml as init parameter 
     int size = Integer.parseInt(getInitParameter("threadpoolsize")); 
     exec = Executors.newFixedThreadPool(size); 

    } 

    @Override 
    public void doGet(HttpServletRequest rq, HttpServletResponse rs) { 

     rs.setContentType("text/plain"); 
     rs.setHeader("Access-Control-Allow-Origin", "*"); 

     //AsyncContext asy = rq.startAsync(rq, rs); 
     //asy.start(new Client(asy)); 

     final AsyncContext asy = rq.startAsync(); 

     // set the timeout 
     asy.setTimeout(CALLBACK_TIMEOUT); 

     // attach listener to respond to lifecycle events of this AsyncContext 
     asy.addListener(new AsyncListenerImpl(asy)); 

     // spawn some task in a background thread 
     exec.execute(new AsyncServletTaskRunner(asy, this)); 
    } 

    @Override 
    public String getServletInfo() { 
     return "Short description"; 
    } 

    @Override 
    public void process(AsyncContext ctx) throws IOException, ServletException { 
     //do whatever you want to do as process of each thread 
    } 
} 

AsyncServletTaskRunner:

import javax.servlet.AsyncContext; 

public class AsyncServletTaskRunner implements Runnable { 

    /** The ctx. */ 
    private AsyncContext ctx; 

    /** The processor. */ 
    private AsyncServletTaskProcessor processor; 

    public AsyncServletTaskRunner() { 
     super(); 
    } 

    public AsyncServletTaskRunner(AsyncContext ctx, AsyncServletTaskProcessor processor) { 
     this.ctx = ctx; 
     this.processor = processor; 
    } 

    @Override 
    public void run() { 

     try { 
      processor.process(ctx); 
     } catch (Exception e) { 
      try { 
       // redirect to error page or do whatever is needed 
      } catch (Exception e1) { 
       e1.printStackTrace(); 
      } 
     } finally { 
      ctx.complete(); 
     } 
    } 

    public AsyncContext getCtx() { 
     return ctx; 
    } 

    public void setCtx(AsyncContext ctx) { 
     this.ctx = ctx; 
    } 

} 

AsyncListenerImpl:

import java.io.IOException; 

import javax.servlet.AsyncContext; 
import javax.servlet.AsyncEvent; 
import javax.servlet.AsyncListener; 

public class AsyncListenerImpl implements AsyncListener { 

    /** The ctx. */ 
    private AsyncContext ctx; 

    public AsyncListenerImpl() { 
     super(); 
    } 

    public AsyncListenerImpl(AsyncContext ctx) { 
     this.ctx = ctx; 
    } 

    @Override 
    public void onComplete(AsyncEvent event) throws IOException { 
     /** complete() has already been called on the async context, nothing to do */ 
    } 

    @Override 
    public void onTimeout(AsyncEvent event) throws IOException { 
     /** timeout has occured in async task... handle it */ 
     try { 
      // redirect to error page or do whatever is needed 
     } catch (Exception e1) { 
      e1.printStackTrace(); 
     } finally { 
      ctx.complete(); 
     } 
    } 

    @Override 
    public void onError(AsyncEvent event) throws IOException { 
     /** THIS NEVER GETS CALLED - error has occured in async task... handle it */ 
     try { 
      // redirect to error page or do whatever is needed 
     } catch (Exception e1) { 
      e1.printStackTrace(); 
     } finally { 
      ctx.complete(); 
     } 
    } 

    @Override 
    public void onStartAsync(AsyncEvent event) throws IOException { 
     /** async context has started, nothing to do */ 
    } 

} 
+0

當然,你需要一個ExecutorService來執行這些線程。從web.xml讀取一些參數,例如線程超時和線程池大小。 AsyncListenerImpl實現AsyncListener接口來處理異步監聽器的所有進程。 – Braj

+0

嘗試瞭解它,同時我正在用步驟更新我的答案。 – Braj

+0

這不適合我,但謝謝。 –