SocketWrapper#processSocket会创建SocketProcessor任务类,并通过Tomcat线程池处理:
public boolean processSocket(SocketWrapperBase<S> socketWrapper, SocketEvent event, boolean dispatch) { if (socketWrapper == null) { return false; } SocketProcessorBase<S> sc = processorCache.pop(); if (sc == null) { sc = createSocketProcessor(socketWrapper, event); } else { sc.reset(socketWrapper, event); } // 线程池运行 Executor executor = getExecutor(); if (dispatch && executor != null) { executor.execute(sc); } else { sc.run(); } }
createSocketProcessor函数的第二个参数SocketEvent,这里传入OPEN_READ,控制SocketProcessor的行为,不需要再把请求发送到容器进行处理,只需要向浏览器端发送数据,并且重新在这个Socket上监听新的请求。
总结
非阻塞I/O模型可利用很少线程处理大量连接,提高并发度,本质就是通过一个Selector线程查询多个Socket的I/O事件,减少线程的阻塞等待。
异步Servlet机制也是减少线程的阻塞等待,将Tomcat线程和业务线程分开,Tomca线程不再等待业务代码执行完成。
适用场景
发现Tomcat的线程不够了,大量线程阻塞在等待Web应用的处理上,而Web应用又没有优化的空间了,确实需要长时间处理,可尝鲜。
FAQ
异步sevlet内部的业务应用中的IO也需要异步IO支持吧,就像vertx的异步模式,否则都堵塞在业务线程上就没意义了。所以Springboot webflux提供全异步的方案。
一个请求进来之后,若采用异步Servlet处理,原来的请求Tomcat线程被回收,那本身这个请求要再相应给客户端,怎么知道是哪个客户端请求过来的,是根据请求信息,一个请求绑定了一个TCP连接,获取客户端地址,响应给客户端。