我想知道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