我想知道Tomcat 7如何實現異步處理。我知道請求線程立即返回,允許請求線程立即偵聽新請求並對其進行響應。Tomcat 7異步處理
如何處理'異步'請求?是否有獨立的線程池來處理異步請求?我認爲阻塞IO處理使用類似java.nio.Selector的性能。 CPU計算阻塞的線程怎麼樣?
我想知道Tomcat 7如何實現異步處理。我知道請求線程立即返回,允許請求線程立即偵聽新請求並對其進行響應。Tomcat 7異步處理
如何處理'異步'請求?是否有獨立的線程池來處理異步請求?我認爲阻塞IO處理使用類似java.nio.Selector的性能。 CPU計算阻塞的線程怎麼樣?
你在混淆不同的概念。您必須區分:
ExecutorService
並使用它來進一步處理請求,或者可以創建新的Runnable
,並通過調用AsyncContext.start()
將其提交到獲得的AsyncContext
。對於Tomcat,後一種方法使用在server.xml
中定義的Tomcat線程池。下面的例子概括了它可以如何工作。它只對工作者作業使用一個線程。如果你在並行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=chrome
和http://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);
}
}
感謝您的澄清。關於CometProcessor API,是否有一個線程輪詢所有當前連接以查看哪一個具有「可供讀取的數據」?具體而言,當有10個請求與100個請求時,線程的預期數量是多少?假設這些請求已收到BEGIN事件,但尚未收到READ事件。 http://tomcat.apache.org/tomcat-7.0-doc/aio.html –
@John如果你對家的答案感到滿意,你應該批准它。你應該提出一個新的問題(最終,你可以參考這個問題)。 – JVerstry
HI @JVerstry,說實話,我並不完全滿意答案。對於「異步處理」,我仍然不認爲我對Tomcat的體系結構有很好的理解。 –
你可能想看看這個:http://stackoverflow.com/questions/ 7749350/illegalstateexception-not-supported-on-asynccontext-startasyncreq-res如果你想在Tomcat 7上實現異步處理。有一個轉折點。 – JVerstry