servlet3.0规范中添加了异步处理,即一部分操作处理完成之后,先行把数据返回来,对于另一部分比较耗时的操作可以放置到另外一个线程中进行处理,该线程保留有连接的请求和响应对象,在处理完成之后可以把处理的结果通知到客户端,实例代码如下:



1. import java.io.IOException;  
2. import java.io.PrintWriter;  
3. import java.util.Date;  
4.   
5. import javax.servlet.AsyncContext;  
6. import javax.servlet.AsyncEvent;  
7. import javax.servlet.AsyncListener;  
8. import javax.servlet.ServletException;  
9. import javax.servlet.annotation.WebServlet;  
10. import javax.servlet.http.HttpServlet;  
11. import javax.servlet.http.HttpServletRequest;  
12. import javax.servlet.http.HttpServletResponse;  
13.   
14. /**   
15.  * @Title: AsynServlet.java 
16.  * @Package  
17.  * @Description: TODO
18.  * @author ynb  
19.  * @date 2014-7-24 下午5:07:00 
20.  * @version V1.0   
21.  */  
22.   
23. /**
24.  * @author admin
25.  *
26.  */  
27. @WebServlet(urlPatterns="/demo", asyncSupported=true)  
28. public class AsynServlet extends HttpServlet {  
29. private static final long serialVersionUID = -8016328059808092454L;  
30.       
31. /* (non-Javadoc)
32.      * @see javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
33.      */  
34. @Override  
35. protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {  
36. "text/html;charset=UTF-8");  
37.             PrintWriter out = resp.getWriter();  
38. "进入Servlet的时间:" + new Date() + ".");  
39.             out.flush();  
40.   
41. //在子线程中执行业务调用,并由其负责输出响应,主线程退出  
42. final AsyncContext ctx = req.startAsync();  
43. 200000);  
44. new Work(ctx).start();  
45. "结束Servlet的时间:" + new Date() + ".");  
46.             out.flush();  
47.     }  
48. }  
49.   
50. class Work extends Thread{  
51. private AsyncContext context;  
52.       
53. public Work(AsyncContext context){  
54. this.context = context;  
55.     }  
56. @Override  
57. public void run() {  
58. try {  
59. 2000);//让线程休眠2s钟模拟超时操作  
60.             PrintWriter wirter = context.getResponse().getWriter();           
61. "延迟输出");  
62.             wirter.flush();  
63.             context.complete();  
64. catch (InterruptedException e) {  
65.               
66. catch (IOException e) {  
67.               
68.         }  
69.     }  
70. }

有些时候,我们可能需要客户端和服务器保持长连接的时候,我们可以使用这个特性,让服务器长时间保持客户端的请求以及对客户端的响应,做法如下:

对于异步执行,我们可以添加一个监听器,监听异步执行的状态。


1. ctx.addListener(new AsyncListener() {  
2. @Override  
3. public void onTimeout(AsyncEvent arg0) throws IOException {  
4. // TODO Auto-generated method stub  
5.       
6. }  
7.   
8. @Override  
9. public void onStartAsync(AsyncEvent arg0) throws IOException {  
10. // TODO Auto-generated method stub  
11.       
12. }  
13.   
14. @Override  
15. public void onError(AsyncEvent arg0) throws IOException {  
16. // TODO Auto-generated method stub  
17.       
18. }  
19.   
20. @Override  
21. public void onComplete(AsyncEvent arg0) throws IOException {  
22. // TODO Auto-generated method stub  
23.       
24. }  
25. );


在Servlet返回之前,我们可以把持有request和response对象的AsyncContext对象放置到一个全局可访问的静态容器中




1. map.put("id",ctx);


如果连接出错或者连接完的时候我们可以在onError以及onComplete方法中移除掉对应连接的AsyncContext



1. map.remove("id",ctx);


在超时的回调方法onTimeout中,我们可以往浏览器发送指定的信息,让客户端重新发起请求,这样就可以保持客户端和服务器的长久连接。

如下服务器和客户端之间数据交互的模型图