版权声明:原创文章,未经允许不得转载.Tips:传统电商火热的时代已经成为过去 , 下一个阶段属于大数据 人工智能 , 服务、便捷、安全、效率、创新成为下一个阶段互联网时代的新词汇,而IT技术也随着行业的变化发展而不断更迭。对于码农的出路总结一句话:追技术不如追领域。[基础][设计][能力] https://blog.csdn.net/shengqianfeng/article/details/84667056
Servlet3是Tomcat7出现的新特性,所以使用的tomcat版本不能低于7.0.
由于每个request请求进来之后都被分配了一个线程处理,如果当前处理的业务方法非常耗时,将会在某段时间出现非常多的线程,而其他请求无法被分配到线程执行而被拒绝,所以Servlet3.0引入了异步支持,请求进来后交给另外一个工作线程去执行,释放当前接入请求的线程,这样就可以接入越来越多的请求,提高并发量。
if (request.isAsyncSupported()) {
//用于启动异步工作线程,进入异步模式,调用业务处理线程进行业务处理
request.startAsync(request, response);
if (request.isAsyncStarted()) {
/**
* 1 获取AsyncContext,对异步执行的上下文提供支持,可以透过AsyncContext的getRequest() 、 getResponse()方法取得Request、Response对象
* 2 客户端的响应将暂缓至,调用AsyncContext的complete()方法或dispatch()为止,前者表示回应完成,后者表示将响应调派给指定的URL
* 3 使用异步处理方式,web容器的请求处理线程释放了,可以服务其他的请求处理。但是该Request的处理并没有结束,
* 在使用AsyncContext的complete或者dispatch完成后,这个request的处理才结束。
*
*/
final AsyncContext asyncContext = request.getAsyncContext();
asyncContext.setTimeout(SysConfig.getInstance().getPropertyInt("async_timeout"));
// Servlet不会被阻塞,而是直接往下执行
asyncContext.start(
// 开启http线程
new Runnable() {
@Override
public void run() {
PrintWriter printWriter = null;
try {
logger.info("休眠3秒钟...");
Thread.sleep(3000);
String responseMsgContent = "";
String ws_callback = SysConfig.getInstance().getProperty("ws_callback");
String result = HttpUtils.postHttpAndHttps(ws_callback, "desc="+System.currentTimeMillis()+"-"+RandomUtils.nextInt(0, 9999));
logger.info("线程Name:{},result:{}",Thread.currentThread().getName(),result);
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-type","application/json;charset=UTF-8");
printWriter = response.getWriter();
printWriter.write(responseMsgContent);
logger.info(responseMsgContent);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (printWriter != null) {
printWriter.flush();
printWriter.close();
}
//告诉启动异步处理的Servlet异步处理已完成,Servlet就会提交请求响应
asyncContext.complete();
}
}
});
logger.info("继续执行....");
}
} else { // 不支持异步
logger.info("当前servlet容器不支持异步....");
}
以上的asyncContext.start(new Runnable(){});这个方法是将任务提交给了主线程池,这样的话感觉不过还是使用的主线程池的线程数,可能效果不是很好。
我们也可以使用自定义线程池,将需要异步处理的任务提交给线程池管理,灵活调用。
package com.jeff.nio.controller;
import java.io.PrintWriter;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import javax.servlet.AsyncContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.jeff.nio.server.common.JsonDto;
/**
* 登录
*
*/
@Controller
public class TestController {
private static final Logger logger = LoggerFactory.getLogger(TestController.class);
private static ThreadPoolExecutor executor = new ThreadPoolExecutor(100, 200, 50000L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(100));
@GetMapping(value="/servlet3.0/asyncContext")
public @ResponseBody void startServer(HttpServletRequest request, HttpServletResponse response) {
JsonDto jsonDto = new JsonDto();
try {
logger.info("start server...................");
if (request.isAsyncSupported()) {
//用于启动异步工作线程,进入异步模式,调用业务处理线程进行业务处理
request.startAsync(request, response);
if (request.isAsyncStarted()) {
/**
* 1 获取AsyncContext,对异步执行的上下文提供支持,可以透过AsyncContext的getRequest() 、 getResponse()方法取得Request、Response对象
* 2 客户端的响应将暂缓至,调用AsyncContext的complete()方法或dispatch()为止,前者表示回应完成,后者表示将响应调派给指定的URL
* 3 使用异步处理方式,web容器的请求处理线程释放了,可以服务其他的请求处理。但是该Request的处理并没有结束,
* 在使用AsyncContext的complete或者dispatch完成后,这个request的处理才结束。
*
*/
final AsyncContext asyncContext = request.getAsyncContext();
asyncContext.setTimeout(5000);
// Servlet不会被阻塞,而是直接往下执行
executor.execute(new Runnable() {
@Override
public void run() {
PrintWriter printWriter = null;
try {
logger.info("休眠3秒钟...");
Thread.sleep(3000);
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-type","application/json;charset=UTF-8");
printWriter = response.getWriter();
printWriter.write(jsonDto.toString());
} catch (Exception e) {
e.printStackTrace();
} finally {
if (printWriter != null) {
printWriter.flush();
printWriter.close();
}
//告诉启动异步处理的Servlet异步处理已完成,Servlet就会提交请求响应
asyncContext.complete();
}
}
});
logger.info("继续执行....");
}
} else { // 不支持异步
logger.info("当前servlet容器不支持异步....");
}
} catch (Exception e) {
e.printStackTrace();
jsonDto.setCode("-1");
jsonDto.setMsg("执行失败");
}
}
}