Servlet 3.0中AsyncContext.start(...)的用途是什么?

时间:2012-04-09 12:45:33

标签: servlets servlet-3.0

Servlet API说“AsyncContext.start”:

  

void start(java.lang.Runnable run)

     

使容器可能从托管线程池调度线程,以运行指定的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 个答案:

答案 0 :(得分:14)

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

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

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

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

答案 1 :(得分:10)

我起初有同样的反应 - 如果你只是把工作转移到另一个线程,你会得到什么?该规范对解释为什么这是一个好主意没有多大帮助。但是this post做得很好。基本上,它是让服务器在高负载下正常降级而不是因为线程耗尽而失败。实际工作是在固定大小的线程池中完成的,因此服务器可以接受任意数量的请求,而不必为每个请求保留一个线程,直到完成为止。当然,您可能需要调整O / S设置才能一次打开数千个套接字。

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

答案 2 :(得分: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 */ });

当然,您可以在非servlet线程中发送响应,但这有一个缺点 - 您使用非servlet线程来执行servlet典型操作,这意味着您将隐式更改线程数量之间的平衡为servlet工作与其他工作保留的权力。

换句话说 - 它使您能够将Runnable发布到servlet线程池中。显然这些是罕见的需求,但仍然 - 它为AsyncContext.start()方法提供了一些推理。

答案 3 :(得分:0)

Tomcat ThreadPoolExecutor基于java.util.concurrent.ThreadPoolExecutor并在Apache Tomcat 8 Configuration Reference中配置。它处理所有Tomcat请求,因此,如果您有长时间运行的任务,最好在自己的小型固定/缓存线程池中处理它们并提交described here之类的任务。