【问题标题】:Async Servlet Feature of Servlet 3 -- how do i handle the time consuming taskServlet 3 的异步 Servlet 特性——我如何处理耗时的任务
【发布时间】:2014-07-24 16:27:54
【问题描述】:

这些天我正在学习 Servlet 3.0 Async Feature,主要思想是将绑定到 Http 线程的任务释放到另一个线程,以便 Http 线程可以回到 Http 线程池(不会阻塞长任务处理),那么你的应用程序可能会更敏感。这里一切顺利。


我找到了两种处理耗时任务的方法

  1. acontext.start()

      asyncContext.start(new Runnable() {
            @Override
            public void run() {
                serviceImpl(req, resp, adapter, context, isNotLeakScan);
            }
        });
    

    官方文档说: acontext.start(new Runnable() {...}) gets a new thread from the container.

  2. 使用 BlockingQueue ,然后新建一个 Tread 来处理队列中的可运行对象。

    private static final BlockingQueue queue = new LinkedBlockingQueue();
    
    
    thread = new Thread(new Runnable() {
    @Override
    public void run() {
    while (true) {
      try {
        Thread.sleep(2000);
        AsyncContext context;
        while ((context = queue.poll()) != null) {
          try {
            ServletResponse response = context.getResponse();
            response.setContentType("text/plain");
            PrintWriter out = response.getWriter();
            out.printf("Thread %s completed the task",  
            Thread.currentThread().getName());
            out.flush();
          } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
          } finally {
            context.complete();
          }
        }
      } catch (InterruptedException e) {
        return;
      }
    }
    

    }


我的问题是:

  • 这两种方法有什么区别?

  • 第一个是否处理了对 Tomcat 容器的任务管理(假设我们已经在 Tomcat 上部署了应用)

  • 第二种方式只是显示手动处理任务的方式?

【问题讨论】:

    标签: java multithreading tomcat servlets asynchronous


    【解决方案1】:

    不同的是:

    (1) 在 servlet 线程池中执行你的慢任务,导致 servlet 池饥饿(至少 Tomcat/Jetty 就是这种情况)。这意味着如果您将 serviceImpl(req, resp, adapter, context, isNotLeakScan); 替换为 Thread.sleep(Long.MAX_VALUE); 并尝试从浏览器连接到 Tomcat 200 次(200 是默认线程数) - Tomcat 将永远挂起,不再接受任何 HTTP 连接。

    (2) 手动为每个任务生成一个线程。

    您通常不希望手动生成线程、轮询队列等。相反,您会使用 Executors 框架,它在后台具有队列实现,并且基于内部线程池。

    @WebServlet(urlPatterns = {"/slowServlet"}, asyncSupported = true)
    public class SlowServlet extends javax.servlet.http.HttpServlet {
    
        protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
            final AsyncContext acontext = request.startAsync();
            ServletContext appScope = request.getServletContext();
            ((Executor) appScope.getAttribute("executor")).execute(() -> {
                try {
                    Thread.sleep(10000); // your slow running task
                    acontext.getResponse().getWriter().print("Done");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
        }
    }
    

    而servlet上下文监听器是(这里是硬编码线程池的大小)

    @WebListener
    public class ExecutorListener implements ServletContextListener {
    
        public void contextInitialized(ServletContextEvent sce) {
            Executor executor = Executors.newFixedThreadPool(10);
            sce.getServletContext().setAttribute("executor", executor);
        }
    
        public void contextDestroyed(ServletContextEvent sce) {
            // add executor fancy shutdown logic here
        }
    }
    

    【讨论】:

    • 您从哪一点知道“Servlet 线程池”中的(1)执行任务?哪种方式更好?谢谢你的回复~~ :D
    • (1) http://java.dzone.com/articles/limited-usefulness + 我在 Tomcat 中没有看到单独的线程池来运行异步任务。哪种方式更好 - 我的,因为它不使用 servlet 线程来处理运行缓慢的任务,也不会重新发明阻塞队列和线程池
    • 我已经阅读了这篇文章,这就是为什么我深入研究 Servlet 的异步内容以找出原因,我没有找到其他证据表明 AsyncContext.start() 除了这篇文章没有用,所以它可能错了。
    猜你喜欢
    • 2011-12-19
    • 1970-01-01
    • 2011-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-13
    相关资源
    最近更新 更多