Tomcat 7异步处理

Joh*_*eng 13 performance multithreading tomcat asynchronous

我想知道Tomcat 7如何实现异步处理.我理解请求线程立即返回,允许请求线程立即侦听新请求并响应它.

如何处理"异步"请求?是否有一个单独的线程池来处理异步请求?我假设阻塞IO是使用java.nio.Selector之类的东西来处理性能的.那些阻塞CPU计算的线程呢?

hom*_*ome 41

你正在混淆不同的概念.你必须区分:

  1. 根据Servlet 3.0进行异步请求处理 ; 一个API,使您可以将传入的servlet请求与Web容器线程池分离.它不会动态创建任何线程.接口的用户可以实现适当的多线程解决方案.它与非阻塞IO无关.
  2. 线程池 ; 提供了一种获取和管理Web容器中的线程的机制.说到异步请求处理,您有2个选项.您可以定义自己的ExecutorService并使用它来进一步处理请求,或者您可以创建一个新的RunnableAsyncContext通过调用将其提交给获得的请求AsyncContext.start().在Tomcat的情况下,后一种方法使用Tomcat中定义的线程池server.xml.
  3. 非阻塞IO(NIO) ; 虽然它是异步的,但它是一个不同的故事.它涉及非阻塞IO操作,如磁盘或网络IO.如果要为HTTP请求处理启用NIO,请查看Tomcat的文档.

以下示例概述了它如何工作.它只使用一个线程进行工作.如果你从两个不同的浏览器并行运行它,输出看起来像这样(我使用自定义记录器):

   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
Run Code Online (Sandbox Code Playgroud)

您看到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);
    }
}
Run Code Online (Sandbox Code Playgroud)

......和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);
    }
}
Run Code Online (Sandbox Code Playgroud)