学习笔记:Sevlet3异步 和 Spirng对Servlet3
2021-01-16 本文已影响0人
瓢鳍小虾虎
使用异步机制处理请求是非常有用的,可以更好的利用cpu资源,提高程序吞吐量。因为通常的请求处理都是单线程的,请求线程是由tomcat分配的,如果业务处理要经过io操作等耗时较长的任务,线程就会一直被占用,tomcat线程池容易被占满,但是cpu并没有充分发挥效能。
Servlet3提供了对请求异步处理的机制。底层就是利用FutureTask的原理。Spirng框架也对Servlet3做了封装,从而更方便开发者使用。
import javax.servlet.AsyncContext;
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 java.io.IOException;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@WebServlet(value = "/servlet3/test", asyncSupported = true)
public class Servlet3Demo extends HttpServlet {
private static ThreadPoolExecutor executor =
new ThreadPoolExecutor(100, 200, 5000L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(200));
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
AsyncContext asyncContext = req.getAsyncContext();
// 记得使用线程池控制多线程操作。
executor.execute(() ->{
try {
Thread.sleep(1000L); // 模拟业务
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
asyncContext.getResponse().getWriter().write("response string");
} catch (IOException e) {
e.printStackTrace();
}
asyncContext.complete();
});
// asyncContext.start(() -> {
// try {
// Thread.sleep(1000L); // 模拟业务
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
//
// try {
// asyncContext.getResponse().getWriter().write("response string");
// } catch (IOException e) {
// e.printStackTrace();
// }
// asyncContext.complete();
// });
}
}
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@RestController
public class SpringSevlet3ControllerDemo {
private LinkedBlockingDeque<DeferredResult> quene = new LinkedBlockingDeque<>();
ThreadPoolExecutor executor =
new ThreadPoolExecutor(100, 200, 5000L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(200));
@GetMapping("/deferredresult/test")
public DeferredResult<String> getSomeResult() {
final DeferredResult<String> deferredResult = new DeferredResult<>(3000L); // 超时时间3秒
quene.add(deferredResult);
executor.submit(()->{
try {
Thread.sleep(1000L); // 模拟业务
} catch (InterruptedException e) {
e.printStackTrace();
}
String rs = "结果123";
deferredResult.setResult(rs);
});
deferredResult.onTimeout(()->{
// 超时业务代码
String rs = "超时了";
deferredResult.setResult(rs);
});
deferredResult.onCompletion(()->{
// 完成后,移除quene队列
quene.remove();
});
return deferredResult;
}
@Scheduled(fixedRate = 1000)
public void scheduleResult(){ // 扫描队列
for (int i = 0; i <quene.size() ; i++) {
DeferredResult<String> stringDeferredResult = quene.poll();
stringDeferredResult.setResult("result:"+i);
}
}
}