Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/visual-studio-2012/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Servlets Tomcat7:异步Servlet不工作_Servlets_Tomcat7 - Fatal编程技术网

Servlets Tomcat7:异步Servlet不工作

Servlets Tomcat7:异步Servlet不工作,servlets,tomcat7,Servlets,Tomcat7,我已经将Tomcat7配置为一个连接器线程,将作业发布到后台线程池中,后台线程异步完成请求。每个请求都有1秒的延迟。我的测试(JMeter)向上旋转5个线程并同时发出5个请求。我希望单连接器线程能够立即处理5个请求中的每一个。相反,它会等待上一个任务(在bg线程上运行)完成,然后再为下一个任务提供服务 为了澄清这一点,我的配置试图模仿Node.js和Tornado等“单线程”异步服务器的线程体系结构 连接器: @WebServlet(asyncSupported = true, value =

我已经将Tomcat7配置为一个连接器线程,将作业发布到后台线程池中,后台线程异步完成请求。每个请求都有1秒的延迟。我的测试(JMeter)向上旋转5个线程并同时发出5个请求。我希望单连接器线程能够立即处理5个请求中的每一个。相反,它会等待上一个任务(在bg线程上运行)完成,然后再为下一个任务提供服务

为了澄清这一点,我的配置试图模仿Node.js和Tornado等“单线程”异步服务器的线程体系结构

连接器:

@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的目的是将连接器线程池与处理线程池解耦,这样,如果请求延迟很长,连接器线程就不会浪费(可以返回)。那么异步的好处是什么呢