启用了异步支持的Servlet,异步支持用到的线程类

package com.jadyer.servlet;



import java.io.IOException;

import java.io.PrintWriter;

import java.util.Date;



import javax.servlet.AsyncContext;

import javax.servlet.AsyncEvent;

import javax.servlet.AsyncListener;

import javax.servlet.ServletException;

import javax.servlet.annotation.WebServlet;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;



import com.jadyer.thread.HelloAsyncThread;



/**

 * Servlet3.0新特性之异步支持

 * @see -------------------------------------------------------------------------------------------------

 * @see 异步实现概述

 * @see 1)Servlet2.5中也可以单独启动一个线程去执行耗时的任务,接着Servlet会继续往下执行

 * @see   执行完最后一行代码时,Servlet就会把响应输出给请求方,而那个线程的任何执行结果都不会反映给请求方

 * @see 2)Servlet3.0中的异步支持也是单独启动线程执行耗时任务,当Servlet执行到最后一行代码时

 * @see   Servlet3.0提供了一些机制会判断那个线程是否执行完毕,直到线程执行完毕后才会响应所有结果给请求方

 * @see   (故本例中浏览器访问Servlet时,它会先转圈即正在加载...,直到5秒后异步线程执行完毕,浏览器才显示出了四行时间)

 * @see 3)若不单独启动线程去执行耗时任务,而是将耗时操作串行放到Servlet方法中执行的话,也是不可取的

 * @see   因为Servlet容器会管理着一个线程池,处理我们请求的Servlet所依附的线程都是来自于这个线程池的

 * @see   如果某个操作过于耗时,那么线程池里面的资源就会被占用掉,所以Servlet3.0就有了异步支持

 * @see -------------------------------------------------------------------------------------------------

 * @see 异步实现步骤

 * @see 1)在Servlet中开启异步支持(默认是不支持异步的),@WebServlet(asyncSupported=true)

 * @see 2)在Servlet中启动一个异步的上下文对象,AsyncContext context = request.startAsync();

 * @see 3)单独创建一个线程执行耗时操作,注意耗时操作执行完毕要调用AsyncContext.complete();

 * @see 4)在Servlet中启动耗时操作的线程

 * @see -------------------------------------------------------------------------------------------------

 * @create Jun 23, 2013 5:47:55 PM

 * @author 玄玉<http://blog.csdn.net/jadyer>

 */

@WebServlet(urlPatterns={"/hello/async"}, asyncSupported=true)

public class HelloAsyncServet extends HttpServlet {

	private static final long serialVersionUID = 3314056681141922826L;

	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

		//获取当前方法的名字

		String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();



		PrintWriter out = response.getWriter();

		out.println(methodName + " starts: " + new Date());

		out.flush();

		System.out.println("第一步mark");



		//启动一个异步操作的上下文对象AsyncContext

		AsyncContext context = request.startAsync();

		//添加一个监听器(奇怪:AsyncListener竟然没有适配器)

		context.addListener(new AsyncListener(){

			@Override

			public void onComplete(AsyncEvent asyncEvent) throws IOException {

				PrintWriter out = asyncEvent.getSuppliedResponse().getWriter();

				out.println("async succes: " + new Date());

				out.flush();

				/**

				 * 在这里关闭流(此处为重点)

				 * @see -------------------------------------------------------------------------------------

				 * @see 总结:自打请求进入doGet()方法中开始,直到请求方收到响应为止

				 * @see     整个过程中的任意位置所获得的PrintWriter和ServletResponse对象都是相同的

				 * @see 说明:在5个步骤mark位置,均执行System.out.println(PrintWriter或ServletResponse对象);

				 * @see     我们会发现在五个mark位置的这俩对象的hashCode和内存地址都是相同的

				 * @see 并且:第一个mark处声明的PrintWriter对象不能在第二个mark处关闭,只能在第4个或第5个mark处关闭

				 * @see     否则异步支持就会失败

				 * @see 补充:第5个mark处的out.println()也会作为响应结果给请求方,这点要注意

				 * @see -------------------------------------------------------------------------------------

				 */

				out.close();

				System.out.println("第五步mark");

			}

			@Override

			public void onError(AsyncEvent arg0) throws IOException {}

			@Override

			public void onStartAsync(AsyncEvent arg0) throws IOException {}

			@Override

			public void onTimeout(AsyncEvent arg0) throws IOException {}

		});

		//也可以用这种方法启动异步线程

		//context.start(new HelloAsyncThread(context));

		new Thread(new HelloAsyncThread(context)).start();



		out.println(methodName + "   ends: " + new Date());

		out.flush();

		System.out.println("第二步mark");

	}

}

最后是异步支持用到的线程类

 

 

package com.jadyer.thread;



import java.io.PrintWriter;

import java.util.Date;



import javax.servlet.AsyncContext;



/**

 * Servlet3.0新特性之异步支持用到的线程类

 * @create Jun 23, 2013 6:05:55 PM

 * @author 玄玉<http://blog.csdn.net/jadyer>

 */

public class HelloAsyncThread implements Runnable {

	private AsyncContext context;



	public HelloAsyncThread(AsyncContext context){

		this.context = context;

	}



	@Override

	public void run() {

		try {

			PrintWriter out = context.getResponse().getWriter();

			out.println("async starts: " + new Date());

			out.flush();

			System.out.println("第三步mark");



			//模拟耗时操作,让线程睡5s

			Thread.sleep(5000);



			out.println("async   ends: " + new Date());

			out.flush();

			System.out.println("第四步mark");



			//调用complete()表明异步处理已完成

			//它会让Servlet知道异步处理已完毕,否则Servlet还在傻傻等待,浪费时间

			context.complete();

		} catch (Exception e) {

			e.printStackTrace();

		}

	}

}





来源http://www.cnblogs.com/Augusdi/archive/2013/06/24/3153175.html
本文链接地址: 启用了异步支持的Servlet,异步支持用到的线程类