21

Servlet API 说“AsyncContext.start”:

无效开始(java.lang.Runnable 运行)

使容器调度线程(可能来自托管线程池)以运行指定的 Runnable。容器可以将适当的上下文信息传播到 Runnable。

从这个描述中,不清楚当作业需要等待时它与优化线程使用的任务有何关系。

在“Servlet & JSP”中,Budi Kurniawan 给出了 Servlet 3.0 异步特性的示例,在他使用的地方AsyncContext.start,我将展示示例的简化版本:

public void doGet(...) {
    final AsyncContext asyncContext = request.startAsync();

    asyncContext.start(new Runnable() {                        
        @ Override
        public void run() {
            // do some work here which involves waiting
            ...
            asyncContext.complete();
        }
    });
}

在我遇到的大多数其他示例中,服务方法只是将 AsyncContext 存储在某处,并在其他地方进行处理(例如,由后台线程)。在此示例中,该作业看起来只是传递给另一个线程,该线程完成了请求。据我了解,现在它只是工作线程,浪费时间等待。

通过将工作(包括等待)从一个线程传递到另一个线程,您真的获得了一些东西吗?如果不是,那它的目的是AsyncContext.start(...)什么?

4

4 回答 4

18

你找到了一个糟糕的例子,恕我直言。事实上,我什至不知道AsyncContext.start()存在。

我快速浏览了JettyTomcat如何实现这一点。事实上,它们似乎有一些独立处理异步调用的线程池。

API 的这种使用不会给您带来任何好处或很少。不是阻塞 HTTP 线程,而是阻塞其他线程池。所以我可以想象应用程序仍然接受新的连接,但问题仍然存在——容器无法处理它们,因为额外的线程池仍然有限。

的全部要点AsyncContext是能够通过单个线程处理多个请求。通常您只需要一个线程来处理数千个异步连接 - 例如,当恰好一个线程等待假设要广播给多个客户端的数据时。另请参阅AsyncContext.start() 的有限用途

于 2012-04-09T13:07:45.277 回答
13

一开始我也有同样的反应——如果你只是将工作传递给另一个线程,你会得到什么?该规范在解释为什么这是一个好主意方面没有多大帮助。但是这篇文章做得很好。基本上,它是让服务器在重负载下优雅地降级,而不是仅仅因为线程耗尽而失败。实际工作是在一个固定大小的线程池中完成的,因此服务器可以接受任意数量的请求,而不必为每个请求保留一个线程直到它完成。当然,您可能必须调整您的 O/S 设置才能同时保持打开数千个套接字。

一旦拥有了这种能力,您就可以更轻松地利用 Comet(服务器推送)架构,其中客户端 Javascript 保持 AJAX 请求打开,以便服务器可以在某些事件发生时立即通知它,而不必轮询服务器以查明是否发生了什么事。

于 2012-06-07T14:20:37.583 回答
0

这可能有用的一个原因是,当您想要释放传入的 Web 线程,做一些其他工作,完成后 - 返回到 Web 线程(可能是另一个线程,但仍然来自 Web 服务器池)以完成原始操作并向客户端发送响应。

例如:

1. ac = request.startAsync();
2. forward("some data", "another system"); // async outbound HTTP request
3. (at this point, incoming servlet thread is released to handle other requests)
4. (in some other, non-servlet thread, upon "forward" response arrival)
   ac.start(new Runnable() { /* send response to the client */ });

You could, of course, send response in the non-servlet thread, but this has one disadvantage - you use non-servlet thread to do servlet-typical operations, which means you're implicitly changing the balance between amount of thread power reserved for servlet work vs. other work.

In other words - it gives you the ability to post Runnable into servlet thread pool. Obviously these are rare needs, but still - it gives some reasoning for AsyncContext.start() method.

于 2014-07-10T21:15:33.503 回答
0

Tomcat ThreadPoolExecutor based on java.util.concurrent.ThreadPoolExecutor and configured in Apache Tomcat 8 Configuration Reference. It handles all Tomcat request, so, if you have long running task its better to handle them in own small-size Fixed/Cached thread pool and submit task like described here.

于 2017-05-20T12:23:13.543 回答