当前位置: 首页 > 知识库问答 >
问题:

异步servlet不在单独的线程中执行异步任务[重复]

翟曦之
2023-03-14

我正在探索使用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
    }

}

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

共有1个答案

令狐宣
2023-03-14

doGet方法中,您已经创建了一个AsyncContext,您有责任将它进一步传递给一个不同的线程,该线程将通过设置result-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,您可以实现一个控制器,它返回一个可调用,Spring Framework将确保调用是在一个生命周期由Spring管理的不同线程中执行的。

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

 类似资料:
  • 当我调用foo()时,这个方法是否在单独的线程上运行?

  • 这是在一次Android采访中被问到的。有人问我是否可以从异步任务 1 的 doInBackground() 方法(让它成为 Task1)启动另一个异步任务(让它成为 Task2)。我浏览了文档,其中说了以下内容: 必须在UI线程上创建任务实例。 必须在 UI 线程上调用 execute(Params...)。 根据这些陈述,我认为从另一个任务的后台方法启动一个任务是不可能的。此外,async任务

  • 在Server程序中如果需要执行很耗时的操作,比如一个聊天服务器发送广播,Web服务器中发送邮件。如果直接去执行这些函数就会阻塞当前进程,导致服务器响应变慢。 Swoole提供了异步任务处理的功能,可以投递一个异步任务到TaskWorker进程池中执行,不影响当前请求的处理速度。 程序代码 基于第一个TCP服务器,只需要增加onTask和onFinish 2个事件回调函数即可。另外需要设置task

  • 本文向大家介绍C#异步执行任务的方法,包括了C#异步执行任务的方法的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了C#异步执行任务的方法。分享给大家供大家参考。具体如下: 希望本文所述对大家的C#程序设计有所帮助。

  • 问题内容: 我正在Flask中编写一个应用程序,除了同步和阻塞之外,它的运行情况非常好。我特别有一项任务,该任务调出第三方API,该任务可能需要几分钟才能完成。我想拨打该电话(实际上是一系列电话)并使其运行。同时控制权返回给Flask。 我的看法如下: 现在,我要做的就是 运行并提供在方法返回时要执行的回调,而Flask可以继续处理请求。这是我需要Flask异步运行的唯一任务,并且我想就如何最好地

  • 我在StackOverflow的职业生涯中有一个第一个问题。我希望是你帮我。 发生了什么: