Java - Servlet 3.0 中的异步与 Servlet 3.1 中的 NIO
Java - Async in Servlet 3.0 vs NIO in Servlet 3.1
直到现在,因为它适用于为 http 请求提供服务,所以我认为术语 - asynchronous
和 non-blocking i/o
意思相同。但显然,它们分别在 servlet 3.0 和 3.1 中分别实现了。我很难理解这里的区别...
有人可以更清楚地说明这个话题吗?具体来说,我正在寻找一个服务器的 servlet 3.0 实现如何异步但阻塞线程的示例?我想如果我理解了这一点,可能更容易理解 servlet 3.1 中的非阻塞 i/o 试图解决的确切问题。
我会尽量总结我学到的东西。要理解Servlet 3.0和Servlet 3.1解决的问题,我们这样看:
Servlet 3.0 之前的版本:
同步处理请求的问题在于,它会导致线程(执行繁重的工作)运行 在响应消失之前长时间运行。如果这种情况大规模发生,servlet 容器最终会耗尽线程 - 长 运行 线程会导致线程饥饿。
在 Servlet 3.0 之前,这些长 运行 线程有特定于容器的解决方案,我们可以在其中生成一个单独的工作线程来完成繁重的任务,然后 return 响应客户端。 servlet 线程returns 启动工作线程后进入servlet 池。 Tomcat的Comet、WebLogic的FutureResponseServlet和WebSphere的Asynchronous Request Dispatcher都是异步处理的一些实现例子。
(有关详细信息,请参阅 link 1。)
Servlet 3.0 异步:
实际工作可以委托给线程池实现(独立于容器特定解决方案)。 Runnable
实现将执行实际处理,并将使用 AsyncContext
将请求分派到另一个资源或写入响应。我们也可以在AsyncContext对象中添加AsyncListener实现来实现回调方法。
(有关详细信息,请参阅 link 1。)
Servlet 3.1 NIO:
如上所述,Servlet 3.0 允许异步请求处理,但只允许传统的 I/O(与 NIO 相反)。为什么传统的 I/O 是个问题?
在传统的I/O中,有两种情况需要考虑:
- 如果进入服务器 (I/O) 的数据阻塞或流式传输速度比服务器读取速度慢,则尝试读取此数据的服务器线程必须等待该数据。
- 另一方面,如果服务器端响应数据写入
ServletOutputStream
很慢,客户端线程就得等待。在这两种情况下,服务器线程执行传统的 I/O(对于 requests/responses)块。
换句话说,在 Servlet 3.0 中,只有请求处理部分变为异步,而 I/O 服务请求和响应的部分没有。如果有足够多的线程阻塞,这会导致线程饥饿并影响性能。
使用 Servlet 3.1 NIO,此问题已通过 ReadListener
和 WriteListener
接口解决。这些在 ServletInputStream
和 ServletOutputStream
中注册。侦听器具有回调方法,当内容可供读取或可以写入时调用,而 servlet 容器不会阻塞 I/O 线程。因此,这些 I/O 线程被释放,现在可以服务于其他提高性能的请求。
(有关详细信息,请参阅 link 2。)
学分
直到现在,因为它适用于为 http 请求提供服务,所以我认为术语 - asynchronous
和 non-blocking i/o
意思相同。但显然,它们分别在 servlet 3.0 和 3.1 中分别实现了。我很难理解这里的区别...
有人可以更清楚地说明这个话题吗?具体来说,我正在寻找一个服务器的 servlet 3.0 实现如何异步但阻塞线程的示例?我想如果我理解了这一点,可能更容易理解 servlet 3.1 中的非阻塞 i/o 试图解决的确切问题。
我会尽量总结我学到的东西。要理解Servlet 3.0和Servlet 3.1解决的问题,我们这样看:
Servlet 3.0 之前的版本:
同步处理请求的问题在于,它会导致线程(执行繁重的工作)运行 在响应消失之前长时间运行。如果这种情况大规模发生,servlet 容器最终会耗尽线程 - 长 运行 线程会导致线程饥饿。
在 Servlet 3.0 之前,这些长 运行 线程有特定于容器的解决方案,我们可以在其中生成一个单独的工作线程来完成繁重的任务,然后 return 响应客户端。 servlet 线程returns 启动工作线程后进入servlet 池。 Tomcat的Comet、WebLogic的FutureResponseServlet和WebSphere的Asynchronous Request Dispatcher都是异步处理的一些实现例子。
(有关详细信息,请参阅 link 1。)
Servlet 3.0 异步:
实际工作可以委托给线程池实现(独立于容器特定解决方案)。 Runnable
实现将执行实际处理,并将使用 AsyncContext
将请求分派到另一个资源或写入响应。我们也可以在AsyncContext对象中添加AsyncListener实现来实现回调方法。
(有关详细信息,请参阅 link 1。)
Servlet 3.1 NIO:
如上所述,Servlet 3.0 允许异步请求处理,但只允许传统的 I/O(与 NIO 相反)。为什么传统的 I/O 是个问题?
在传统的I/O中,有两种情况需要考虑:
- 如果进入服务器 (I/O) 的数据阻塞或流式传输速度比服务器读取速度慢,则尝试读取此数据的服务器线程必须等待该数据。
- 另一方面,如果服务器端响应数据写入
ServletOutputStream
很慢,客户端线程就得等待。在这两种情况下,服务器线程执行传统的 I/O(对于 requests/responses)块。
换句话说,在 Servlet 3.0 中,只有请求处理部分变为异步,而 I/O 服务请求和响应的部分没有。如果有足够多的线程阻塞,这会导致线程饥饿并影响性能。
使用 Servlet 3.1 NIO,此问题已通过 ReadListener
和 WriteListener
接口解决。这些在 ServletInputStream
和 ServletOutputStream
中注册。侦听器具有回调方法,当内容可供读取或可以写入时调用,而 servlet 容器不会阻塞 I/O 线程。因此,这些 I/O 线程被释放,现在可以服务于其他提高性能的请求。
(有关详细信息,请参阅 link 2。)
学分