【问题标题】:Async Servlets not executing the async task in a separate thread [duplicate]异步 Servlet 不在单独的线程中执行异步任务 [重复]
【发布时间】:2015-11-11 05:30:43
【问题描述】:

我正在探索使用 Spring Boot 的异步 servlet。据我了解,异步 servlet 用于在一个线程中执行长时间运行的任务,而不是容器启动来处理请求的线程,以便容器可以使用自己的线程来处理其他连接。基于这样的理解,我尝试了以下代码:

@WebServlet(asyncSupported = true, urlPatterns = "/demo")
@Component
public class demo extends HttpServlet {



    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
     *      response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        final AsyncContext context = request.startAsync();
        ServletOutputStream stream = response.getOutputStream();
        WriteListener listener = new WriteListener() {

            @Override
            public void onWritePossible() throws IOException {
                System.out.println(Thread.currentThread().getId());
                ServletOutputStream output = context.getResponse().getOutputStream();
                if (output.isReady()) {
                    try {
                        TimeUnit.SECONDS.sleep(10);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    output.print("Heloooooooooo");
                }
                context.complete();
            }

            @Override
            public void onError(Throwable throwable) {
                throwable.printStackTrace(System.err);
                context.complete();
            }
        };

        stream.setWriteListener(listener);
        System.out.println(Thread.currentThread().getId());

    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
     *      response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException,
            IOException {
        // TODO Auto-generated method stub
    }

}

但问题是onWritePossible 方法正在由运行doGet 的同一线程调用。不应该不一样吗?

【问题讨论】:

  • 通常会有两个请求。一个用于主页,另一个用于 websocket(页面加载后由 javascript 触发)
  • 这与 websockets 无关。这是一个异步 Servlet,我正在尝试通过 localhost:8080/demo 访问它

标签: java servlets asynchronous spring-boot nio


【解决方案1】:

在您的doGet 方法中,您创建了一个AsyncContext,您有责任将其进一步传递给另一个线程,该线程将(稍后)通过设置结果来完成处理 - servlet 容器不会创建给你一个新线程。

AsyncContext 被传递给不同的线程后,doGet 可以立即返回释放 servlet 容器的执行线程以处理新请求。

基于您的代码的示例:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
    final AsyncContext context = request.startAsync();
    System.out.println("Servlet container thread before async started: " 
        + Thread.currentThread().getName());
    new Thread(new Runnable() {
        @Override
        public void run() {
                try {
                    System.out.println("New thread started: " 
                         + Thread.currentThread().getName());
                    ServletOutputStream output = context.getResponse().getOutputStream();
                    TimeUnit.SECONDS.sleep(3);
                    System.out.println("New thread writing response: " 
                        + Thread.currentThread().getName());
                    output.print("Hi!");
                    context.complete();
                } catch (Throwable e) {
                    e.printStackTrace();
                }
        }
    }).start();
    System.out.println("Servlet container thread returning: " 
        + Thread.currentThread().getName());
}

输出:

Servlet container thread before async started: http-nio-8080-exec-1
Servlet container thread returning: http-nio-8080-exec-1
New thread started: Thread-3
New thread writing response: Thread-3

如果您使用 Spring Boot,您可以实现一个 Controller,它返回一个 Callable,Spring Framework 将确保 Callable 在另一个线程中执行,该线程的生命周期由 Spring 管理。

如果您想在没有 Spring 的情况下执行此操作(这也可以),通常通过将 AsyncContext 放入队列并让 ExecutorService 使用排队的请求来完成。

【讨论】:

    【解决方案2】:

    你的理解有点不对劲。通常使用异步方法的好处是消耗额外的线程,同时也阻塞处理请求的线程。要从中获得任何真正的好处,您需要在执行 IO 时使用非阻塞 API。

    This question,虽然是在 .NET 技术的背景下被问到的,但应该能有所启发。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多