我看到了这个线程:Java - Async in Servlet 3.0 vs NIO in Servlet 3.1,但它似乎与Servlet 3.1 NIO有关(与Tomcat NIO HTTP连接器相对)。
据我了解,使用NIO HTTP连接器实现(在Tomcat 8及更高版本中为默认设置)配置Tomcat的实际工作是在单独的工作线程上完成处理请求并产生响应的工作,而轮询器线程则读取/写数据保持畅通。
这似乎与Async Servlet 3.0解决的问题相同,因为在请求/响应上完成的工作是在独立于http连接线程的工作线程上完成的。
那么,这是两个解决同一问题的解决方案吗?换句话说,如果Servlet容器已经是异步的,以异步方式编写代码是否有好处?
答案 0 :(得分:1)
通过理解从容器到应用程序代码的请求处理中不同点发生IO的潜在位置,可以更容易理解这一点。容器连接器(BIO / NIO)的工作是接受套接字连接并将其移交给线程,该线程在某个时间点调用Servlet GET / POST方法。现在,Tomcat NIO连接器基本上是容器决定使用Java NIO工具(Selector / Channel)以更少的线程处理多个IO通道。 Selector
提供了一种机制,用于监视一个或多个NIO通道并识别何时有一个或多个NIO通道可用于数据传输,因此使用选择器容器可以使用一个线程而不是多个线程来管理多个通道。这些就绪通道然后由线程服务,这些线程的数量可能少于BIO连接器中所需的数量。
顺便说一句-在此级别进行了OS级别的优化,以改善NIO的功能。例如,Java附带了一个基于Linux epoll事件通知工具的java.nio.channels.SelectorProvider
实现。 epoll
工具在Linux 2.6和更新的内核中可用。当成千上万的Selector注册了SelectableChannel时,新的基于epoll的SelectorProvider实现比传统的基于轮询的SelectorProvider实现更具可伸缩性。当检测到2.6内核时,默认情况下将使用新的SelectorProvider实现。
当检测到2.6之前的内核时,将使用基于轮询的SelectorProvider。
现在回到手头的问题。在Servlet 3.0之前,整个Servlet处理都是同步的,这在Servet 3.0中得到了改进,因此GET / POST方法现在可以立即返回,但无需写入响应,除非通过调用AsyncContext
complete
认为它已完成。 。到目前为止,一切都很好。但是还有另一个问题。 Servlet处理可能包括对请求中可用的输入流/输出流的读/写。此IO的性质仍然是传统的。 Servlet 3.0允许异步请求处理,但IO读/写仍然是旧样式,例如,当以较低速度从客户端读取大请求有效负载时,线程将阻止等待数据-因此Servlet 3.1非阻塞IO可以进行救援现在,只要数据准备就绪,您就可以对读/写逻辑进行回调风格的调用,而不必等待线程等待它。可以在here中看到它在代码中的工作方式。
我们仍然必须记住,数据库IO(如果有)仍然是传统的等待IO。该区域由遵循JDBC API的数据库驱动程序控制,并且他们知道有一天它们也为非阻塞IO提供API。 Oracle已经领导了一项这样的计划Asynchronous Database Access,该计划也似乎正在利用Java NIO。这将为使整个请求处理成为非阻塞铺平道路。