我现在正在学习Servlet 3.0异步功能,它的主要思想是将绑定到Http线程的任务发布到另一个线程,这样Http线程就可以回到Http线程池了(没有阻止长任务处理),那么你的应用程序可能会更具响应性。一切都很好。
我找到了两种处理耗时任务的方法
acontext.start()
asyncContext.start(new Runnable() {
@Override
public void run() {
serviceImpl(req, resp, adapter, context, isNotLeakScan);
}
});
官方文件说:
acontext.start(new Runnable() {...}) gets a new thread from the container.
使用BlockingQueue,然后使用新的Tread处理队列中的runnables。
private static final BlockingQueue queue = new LinkedBlockingQueue();
thread = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(2000);
AsyncContext context;
while ((context = queue.poll()) != null) {
try {
ServletResponse response = context.getResponse();
response.setContentType("text/plain");
PrintWriter out = response.getWriter();
out.printf("Thread %s completed the task",
Thread.currentThread().getName());
out.flush();
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
} finally {
context.complete();
}
}
} catch (InterruptedException e) {
return;
}
}
}
我的问题是:
这两种方法有什么区别?
第一个是否将任务管理处理到Tomcat容器(假设我们已经在Tomcat上部署了应用程序)
第二种方式只是手动显示处理任务的方式?
答案 0 :(得分:2)
区别在于:
(1)在servlet线程池中执行你的慢任务,导致servlet池饥饿(至少是Tomcat / Jetty的情况)。这意味着如果用serviceImpl(req, resp, adapter, context, isNotLeakScan);
替换Thread.sleep(Long.MAX_VALUE);
并尝试从浏览器连接到Tomcat 200次(200是默认线程数) - Tomcat将永远挂起,不接受任何更多HTTP连接。
(2)手动为每个任务生成一个线程。
您通常不想手动生成线程,轮询队列等。相反,您将使用Executors框架,它具有引擎下的队列实现,并且基于内部线程池。
@WebServlet(urlPatterns = {"/slowServlet"}, asyncSupported = true)
public class SlowServlet extends javax.servlet.http.HttpServlet {
protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
final AsyncContext acontext = request.startAsync();
ServletContext appScope = request.getServletContext();
((Executor) appScope.getAttribute("executor")).execute(() -> {
try {
Thread.sleep(10000); // your slow running task
acontext.getResponse().getWriter().print("Done");
} catch (Exception e) {
e.printStackTrace();
}
});
}
}
servlet上下文监听器是(线程池的大小在这里是硬编码的)
@WebListener
public class ExecutorListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent sce) {
Executor executor = Executors.newFixedThreadPool(10);
sce.getServletContext().setAttribute("executor", executor);
}
public void contextDestroyed(ServletContextEvent sce) {
// add executor fancy shutdown logic here
}
}