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

22

Servlet API中关于"AsyncContext.start"的说明:

void start(java.lang.Runnable run)

导致容器派遣一个线程(可能来自托管线程池)运行指定的Runnable,容器可能会向该Runnable传递适当的上下文信息。

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

Budi Kurniawan在"S​​ervlet&JSP"中提供了一个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(...) 的目的是什么?

我也在想同样的事情! - Deadron
4个回答

18

我认为这个例子并不好。实际上,我甚至不知道 AsyncContext.start() 的存在。

我简单看了一下 JettyTomcat 是如何实现这个的。实际上,它们似乎有一些线程池独立地处理异步调用。

这种使用 API 的方式没有任何好处或者只有非常少的好处。与其阻塞 HTTP 线程,你会阻塞其他线程池。因此,我可以想象应用程序仍然接受新连接,但问题依然存在-容器不能处理所有连接,因为额外的线程池仍然受限制。

AsyncContext 的整个目的是能够通过一个线程来处理多个请求。通常,你只需要一个线程来处理成千上万的异步连接-例如当恰好一个线程等待要广播到多个客户端的数据时。另请参见 AsyncContext.start() 的有限用途


这正是我所怀疑的。谢谢! - Aivar
自你回答以来,这个实现有没有进行任何更改? - Sotirios Delimanolis

14

起初我也有同样的反应,如果你只是把工作传递到另一个线程,你会得到什么好处?规范在解释为什么这是个好主意方面没有提供太多帮助。但是这篇文章做得非常好。基本上,它是为了让服务器在重负载下优雅地降级而不是通过耗尽线程而失败。实际工作是在固定大小的线程池中完成的,因此服务器可以接受任何数量的请求,而无需为每个请求保留一个线程,直到它完成。当然,您可能需要调整操作系统设置才能一次保持打开数千个套接字。

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


链接已损坏,找到了这个,也许是你要的:https://www.infoworld.com/article/2077995/java-concurrency-asynchronous-processing-support-in-servlet-3-0.html - puppylpg
@puppylpg 谢谢,我修复了链接。你找到的文章不同,但看起来也很有用。 - John Velonis

0

0

这种方法的一个好处是当你想要释放进入的网络线程,做一些其他的工作,然后完成后回到网络线程(可能是另一个线程,但仍然来自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()方法提供了一些理由。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接