Servlets Tomcat7:异步Servlet不工作
我已经将Tomcat7配置为一个连接器线程,将作业发布到后台线程池中,后台线程异步完成请求。每个请求都有1秒的延迟。我的测试(JMeter)向上旋转5个线程并同时发出5个请求。我希望单连接器线程能够立即处理5个请求中的每一个。相反,它会等待上一个任务(在bg线程上运行)完成,然后再为下一个任务提供服务 为了澄清这一点,我的配置试图模仿Node.js和Tornado等“单线程”异步服务器的线程体系结构 连接器:Servlets Tomcat7:异步Servlet不工作,servlets,tomcat7,Servlets,Tomcat7,我已经将Tomcat7配置为一个连接器线程,将作业发布到后台线程池中,后台线程异步完成请求。每个请求都有1秒的延迟。我的测试(JMeter)向上旋转5个线程并同时发出5个请求。我希望单连接器线程能够立即处理5个请求中的每一个。相反,它会等待上一个任务(在bg线程上运行)完成,然后再为下一个任务提供服务 为了澄清这一点,我的配置试图模仿Node.js和Tornado等“单线程”异步服务器的线程体系结构 连接器: @WebServlet(asyncSupported = true, value =
@WebServlet(asyncSupported = true, value = "/testasync", loadOnStartup = 1)
public class TestAsync extends HttpServlet {
private static final Logger LOG = Logger.getLogger(TestAsync.class.getName());
private static final long serialVersionUID = 1L;
private static final int NUM_WORKER_THREADS = 100;
private ExecutorService executor = null;
@Override
public void init() throws ServletException {
this.executor = Executors.newFixedThreadPool(NUM_WORKER_THREADS);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
final AsyncContext ac = request.startAsync(); // obtain async context
ac.setTimeout(0); // test only, no timeout
LOG.info("received request on: " + Thread.currentThread().getId());
this.executor.execute(new Runnable() {
public void run() {
try {
LOG.info("processing request: "+ Thread.currentThread().getId());
Thread.sleep(5000);
LOG.info("processed request:"+ Thread.currentThread().getId());
ac.getResponse().getWriter().write("<h1>Request Processed</h1>");
ac.complete();
}
catch (Exception e) {
LOG.info("failed:" + e);
}
}
});
LOG.info("posted request on: " + Thread.currentThread().getId());
}
Servlet:
@WebServlet(asyncSupported = true, value = "/testasync", loadOnStartup = 1)
public class TestAsync extends HttpServlet {
private static final Logger LOG = Logger.getLogger(TestAsync.class.getName());
private static final long serialVersionUID = 1L;
private static final int NUM_WORKER_THREADS = 100;
private ExecutorService executor = null;
@Override
public void init() throws ServletException {
this.executor = Executors.newFixedThreadPool(NUM_WORKER_THREADS);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
final AsyncContext ac = request.startAsync(); // obtain async context
ac.setTimeout(0); // test only, no timeout
LOG.info("received request on: " + Thread.currentThread().getId());
this.executor.execute(new Runnable() {
public void run() {
try {
LOG.info("processing request: "+ Thread.currentThread().getId());
Thread.sleep(5000);
LOG.info("processed request:"+ Thread.currentThread().getId());
ac.getResponse().getWriter().write("<h1>Request Processed</h1>");
ac.complete();
}
catch (Exception e) {
LOG.info("failed:" + e);
}
}
});
LOG.info("posted request on: " + Thread.currentThread().getId());
}
@WebServlet(asyncSupported=true,value=“/testasync”,loadOnStartup=1)
公共类TestAsync扩展了HttpServlet{
私有静态最终记录器LOG=Logger.getLogger(TestAsync.class.getName());
私有静态最终长serialVersionUID=1L;
私有静态final int NUM_WORKER_线程=100;
私有executor服务executor=null;
@凌驾
public void init()引发ServletException{
this.executor=Executors.newFixedThreadPool(NUM\u WORKER\u THREADS);
}
受保护的void doGet(HttpServletRequest请求,HttpServletResponse响应)抛出ServletException,IOException{
final AsyncContext ac=request.startAsync();//获取异步上下文
ac.setTimeout(0);//仅测试,无超时
LOG.info(“在:+Thread.currentThread().getId()上收到请求”);
this.executor.execute(new Runnable()){
公开募捐{
试一试{
LOG.info(“处理请求:+Thread.currentThread().getId());
睡眠(5000);
LOG.info(“已处理的请求:+Thread.currentThread().getId());
ac.getResponse().getWriter().write(“已处理请求”);
ac.完成();
}
捕获(例外e){
日志信息(“失败:+e”);
}
}
});
LOG.info(“在:+Thread.currentThread().getId()上发布请求”);
}
}
日志:
@WebServlet(asyncSupported = true, value = "/testasync", loadOnStartup = 1)
public class TestAsync extends HttpServlet {
private static final Logger LOG = Logger.getLogger(TestAsync.class.getName());
private static final long serialVersionUID = 1L;
private static final int NUM_WORKER_THREADS = 100;
private ExecutorService executor = null;
@Override
public void init() throws ServletException {
this.executor = Executors.newFixedThreadPool(NUM_WORKER_THREADS);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
final AsyncContext ac = request.startAsync(); // obtain async context
ac.setTimeout(0); // test only, no timeout
LOG.info("received request on: " + Thread.currentThread().getId());
this.executor.execute(new Runnable() {
public void run() {
try {
LOG.info("processing request: "+ Thread.currentThread().getId());
Thread.sleep(5000);
LOG.info("processed request:"+ Thread.currentThread().getId());
ac.getResponse().getWriter().write("<h1>Request Processed</h1>");
ac.complete();
}
catch (Exception e) {
LOG.info("failed:" + e);
}
}
});
LOG.info("posted request on: " + Thread.currentThread().getId());
}
2013年9月17日下午12:26:00 TestAsync doGet信息:收到的请求日期:16
2013年9月17日下午12:26:00 TestAsync doGet信息:发布请求日期:16
2013年9月17日下午12:26:00 TestAsync$1运行信息:处理请求:26
2013年9月17日下午12:26:05 TestAsync$1运行信息:已处理请求:26
2013年9月17日下午12:26:05 TestAsync doGet信息:收到请求的时间:27
2013年9月17日下午12:26:05 TestAsync doGet信息:发布请求日期:27
2013年9月17日下午12:26:05 TestAsync$1运行信息:处理请求:28
2013年9月17日下午12:26:10 TestAsync$1运行信息:已处理请求:28
2013年9月17日下午12:26:10 TestAsync doGet信息:收到请求的时间:27
2013年9月17日下午12:26:10 TestAsync doGet信息:发布请求日期:27
2013年9月17日下午12:26:10 TestAsync$1运行信息:处理请求:29
2013年9月17日下午12:26:15 TestAsync$1运行信息:已处理请求:29
2013年9月17日下午12:26:15 TestAsync doGet信息:收到请求的时间:27
2013年9月17日下午12:26:15 TestAsync doGet信息:发布请求于:27
2013年9月17日下午12:26:15 TestAsync$1运行信息:处理请求:30
2013年9月17日下午12:26:20 TestAsync$1运行信息:已处理请求:30
2013年9月17日下午12:26:20 TestAsync doGet信息:收到请求的时间:27
2013年9月17日下午12:26:20 TestAsync doGet信息:发布请求日期:27
2013年9月17日下午12:26:20 TestAsync$1运行信息:处理请求:31
2013年9月17日下午12:26:25 TestAsync$1运行信息:已处理请求:31我认为这是由于Tomcat中使用了BIO连接器。这是Tomcat安装中的默认连接器。然后,通过池中的单个线程,您可以看到所描述的行为
如果将
maxThreads
增加到1以上,您将看到其他线程接收传入的请求,但连接器仍会阻止新连接,直到现有线程空闲为止。要移动到您想要的模型(一个请求线程,在您希望将处理委托给另一个线程时被释放),您需要切换到一个不阻塞的连接器(NIO或APR/Native)。您还可能需要增加线程池的大小(这实际上取决于请求处理线程是否只执行一项任务,以及它是否过载)。我认为这是由于Tomcat中使用了BIO连接器。这是Tomcat安装中的默认连接器。然后,通过池中的单个线程,您可以看到所描述的行为
如果将
maxThreads
增加到1以上,您将看到其他线程接收传入的请求,但连接器仍会阻止新连接,直到现有线程空闲为止。要移动到您想要的模型(一个请求线程,在您希望将处理委托给另一个线程时被释放),您需要切换到一个不阻塞的连接器(NIO或APR/Native)。您还可能需要增加线程池的大小(这实际上取决于请求处理线程是否只执行一个作业,以及它是否过载)。您应该使用NIO连接器和执行器池,如前所述
如果你没有真正好的理由;没有理由在前面用一根线来限制自己。请参阅我提供的url。您应该使用所述的NIO连接器和执行器池
如果你没有真正好的理由;没有理由在前面用一根线来限制自己。请参阅我提供的url。我认为异步Servlet的目的是将连接器线程池与处理线程池解耦,这样,如果请求延迟很长,连接器线程就不会浪费(可以返回)。那么异步的好处是什么呢