简述
Servlet3.0提供异步功能,Servlet3.1提供非阻塞IO功能。
使用异步,能快速释放Servlet容器线程池的线程,异步任务交由业务线程池来处理。
开始
import javax.servlet.*;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Date;
import java.util.concurrent.*;
/**
* @program: demo->MysTest
* @description:
* @author: liangshijie
* @create: 2020-10-10 16:52
**/
@WebServlet(urlPatterns = "/", asyncSupported = true)
public class MysTest extends HttpServlet {
/**
* 有效核心处理器
*/
private final static int AVALIABLE_PROCESSORS = Runtime.getRuntime().availableProcessors();
/**
* 核心线程数
*/
private final static int CORE_POOL_SIZE = AVALIABLE_PROCESSORS;
/**
* 最大线程数
*/
private final static int MAX_IMUM_POOL_SIZE = AVALIABLE_PROCESSORS * 2;
/**
* 线程保存时间
*/
private final static long KEEP_LIVE_TIME = 1L;
/**
* 核心线程数及队列满了,就会新建线程
*/
private final static BlockingQueue<Runnable> WORK_QUEUE = new ArrayBlockingQueue<>(5);
/**
* 线程工程,可以指定线程名字以区分业务
*/
private final static ThreadFactory THREAD_FACTORY = new TaskThreadFactory();
/**
* 策略
*/
private final static RejectedExecutionHandler HANDLER = new ThreadPoolExecutor.CallerRunsPolicy();
/**
*
RejectedExecutionHandler handler;
1.抛出异常(默认)AbortPolicy
2.无声地放弃当前任务。DiscardPolicy
3.丢弃队列最靠前的任务。DiscardOldestPolicy
4.用调用者所在的线程来执行任务(除非线程池关闭)CallerRunsPolicy
*/
private final static ExecutorService POOL_EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE, MAX_IMUM_POOL_SIZE
,KEEP_LIVE_TIME, TimeUnit.MINUTES, WORK_QUEUE, THREAD_FACTORY, HANDLER);
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//开启异步,
final AsyncContext asyncContext = req.startAsync();
//监听异步任务
asyncContext.addListener(new AsyncListener() {
@Override
public void onComplete(AsyncEvent asyncEvent) throws IOException {
System.out.println("监听到异步任务完成了");
}
@Override
public void onTimeout(AsyncEvent asyncEvent) throws IOException {
}
@Override
public void onError(AsyncEvent asyncEvent) throws IOException {
}
@Override
public void onStartAsync(AsyncEvent asyncEvent) throws IOException {
System.out.println("开始一个异步任务");
}
});
final ServletInputStream input = req.getInputStream();
//设置读监听
input.setReadListener(new ReadListener() {
/**
* TCP端口缓存有数据时回调。
* 当请求携带有参数的时候,会进入此方法,反之则不进入。
* @throws IOException
*/
@Override
public void onDataAvailable() throws IOException {
byte[] buff = new byte[1 * 1024];
int readBytes = 0;
while ( input.isReady() && !input.isFinished() ) {
readBytes += input.read(buff);
}
System.out.println("request参数大小:" + readBytes);
}
/**
* onDataAvailable()结束之后运行:
* 所有数据读取完
* @throws IOException
*/
@Override
public void onAllDataRead() throws IOException {
POOL_EXECUTOR.execute(()->{
try {
TimeUnit.SECONDS.sleep(3);
resp.setContentType("text/html");
resp.setCharacterEncoding("UTF-8");
PrintWriter printWriter = asyncContext.getResponse().getWriter();
printWriter.println("我是结果:" + new Date());
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//异步任务完成通知
asyncContext.complete();
System.out.println("异步任务完成");
}
});
}
@Override
public void onError(Throwable throwable) {
}
});
System.out.println("先释放容器线程,异步任务在执行...");
}
private static class TaskThreadFactory implements ThreadFactory {
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
return t;
}
}
}
参考《Java异步编程实战》翟陆续