web容器会为每个请求分配一个线程,Servlet3.0新增了异步处理,解决多个线程不释放占据内存的问题。可以先释放容器分配给请求的线程与相关资源,减轻系统负担,原先释放了容器所分配线程的请求,其响应将被延后,可以在处理完成后再对客户端进行响应。
为了支持异步处理,在ServletRequest上提供了startAsync()方法。可以通过AsyncContext的getRequest()和getResponse()方法取得请求、响应对象,此次对客户端的响应将暂缓至调用AsyncContext的complete()或dispatch()方法为止。
首先要告知此容器支持Servlet异步处理,如:
例1:异步处理的例子
AsyncServlet.java
首先告诉容器,这个Servlet支持异步处理,对于每个请求,Servlet会取得其AsyncContext,并释放容器所分配的线程,响应被延迟后。对于这些被延迟后响应的请求,创建一个实现Runnable接口的AsyncRequest对象,并将其调度一个固定数量的线程池,让这些必须长时间处理的请求,在线程池中完成,不用每次分配线程。
例2:AsyncRequest是个实现Runnable的类,其模拟了长时间处理。
AsyncRequest.java
以暂停线程的方式来模拟长时间处理,并输出简单的文字,最后调用complete()对客户端完成响应。
HTTP是基于请求、响应模型,如果客户端要获得服务器的最新状态,就必须以定期方式发送请求,查询服务器端的最新状态。
Servlet 3.0提供的异步处理技术,可以解决每个请求占用线程的问题,再结合Ajax异步请求技术,就可以达到类似服务器主动通知浏览器的行为。这就是所谓的服务器端推播。
例3:模拟应用程序不定期产生最新数据,这个部分由实现ServletContextListener的类负责,会在程序启动时进行。
WebInitListener.java
有个List会存储所有的异步请求的AsyncContext,并在不定时产生数字后,逐一对客户端响应,并调用AsyncContext的conmplete()来完成请求。
负责接收请求的Servlet,一收到请求,就将之加入到List中。
AsyncNumServlet.java
由于List是储存为ServletContext属性,所以在Servlet中,必须从ServletContext中取出,每次请求到来时,调用HttpServletRequest的startAsync()进行异步处理,并取得AsyncContext加入维护AsyncContext的List中。
可以使用一个简单的HTML,使用Ajax技术,发送异步请求值服务器端,这个请求会被延迟,直到服务器端完成响应后,更新网页上的资料,并再度发送异步请求:
async.html
可以试着用多个浏览器请求这个页面,会看到每个浏览器的资料是同步的。
当神已无能为力,那便是魔渡众生