【问题标题】:Controller thread is waiting for the Async method response控制器线程正在等待 Async 方法响应
【发布时间】:2019-11-09 17:02:25
【问题描述】:

我是 Spring Boot 新手,想了解更多有关 DeferredResult 和 @Async 方法的信息。我在控制器中创建了一个方法,如下所示,它运行良好。

   @GetMapping("/temp/{id}")
   public DeferredResult<ResponseEntity<?>> findByIdTemp(@PathVariable Long id) throws InterruptedException {

        System.out.println("Request received : "+Thread.currentThread().getName());
        final DeferredResult<ResponseEntity<?>> deferredResult = new DeferredResult<>();
        ForkJoinPool.commonPool().submit(() -> {
            System.out.println("Processing in separate thread");
            try {
                Thread.sleep(6000);
            } catch (InterruptedException e) {
            }
            deferredResult.setResult(ResponseEntity.ok("ok"));
        });

        System.out.println("Thread freed : " +Thread.currentThread().getName());
        return deferredResult;
    }

以下是我收到的输出。

Request received : http-nio-8080-exec-1
Thread freed : http-nio-8080-exec-1
Processing in separate thread

然后我在服务类中创建@Async 方法并在配置类中启用异步。

@Configuration
@EnableAsync
public class ThreadPoolConfiguration {
    @Autowired
    private ExecutorConfiguration configuration;

    @Bean(name = "threadPool")
    public Executor threadPoolTaskExecutor() {
        ThreadPoolTaskExecutor threadPool = new ThreadPoolTaskExecutor();
        threadPool.setCorePoolSize(configuration.getDnCallBackPoolSize());
        return threadPool;
    }
}
    @Async("threadPool")
    public Future<String> getResult() throws InterruptedException {
        System.out.println("Separate thread : "+Thread.currentThread().getName());
        Thread.sleep(6000);
        return new AsyncResult<>("Success");
    }

然后我从控制器类中调用了服务方法

    @GetMapping("/temp/{id}")
    public DeferredResult<ResponseEntity<?>> findByIdTemp(@PathVariable Long id) {

        System.out.println("Request received : "+Thread.currentThread().getName());
        final DeferredResult<ResponseEntity<?>> deferredResult = new DeferredResult<>();
        ResponseDTO responseDTO = null;
        try {
            responseDTO = ResponseDTO.builder()
                    .status(HttpStatus.OK.toString())
                    .body(productService.getResult().get()).build();

            ResponseEntity responseEntity = ResponseEntity.ok(responseDTO);
            deferredResult.setResult(responseEntity);
        } catch (InterruptedException e) {
            System.out.println(e.getMessage());
        } catch (ExecutionException e) {
            System.out.println(e.getMessage());
        }
        System.out.println("Thread freed : " +Thread.currentThread().getName());
        return deferredResult;
    }

但我得到的结果不一样

Request received : http-nio-8080-exec-1
Separate thread : dnCallBackPool-1
Thread freed : http-nio-8080-exec-1

控制器方法似乎正在等待服务方法的响应。谁能告诉我如何正确使用 DeferredResult 和 @Async 方法。

【问题讨论】:

    标签: java spring spring-boot


    【解决方案1】:

    控制器方法似乎正在等待服务方法的响应。

    是的,控制器方法正在等待来自productService的响应,因为来自dnCallBackPool@Async线程只负责执行productService中的getResult()方法。

    但是try-catch块中的代码是由Web容器线程执行的(例如http-nio-8080-exec-1

    responseDTO = ResponseDTO.builder()
                    .status(HttpStatus.OK.toString())
                    .body(productService.getResult()**.get()**).build();
    

    所以Future对象get()调用productService.getResult()是一个阻塞调用,当前线程应该等到@Async线程完成它的过程并返回结果

    如有必要,等待计算完成,然后检索其结果。

    在控制器方法末尾的Future对象上的get()也是如此,以便两个方法并行执行,下面是一个示例

    控制器:

     @GetMapping("/temp/{id}")
    public DeferredResult<ResponseEntity<?>> findByIdTemp(@PathVariable Long id) {
    
        System.out.println("Request received : "+Thread.currentThread().getName());
        final DeferredResult<ResponseEntity<?>> deferredResult = new DeferredResult<>();
    
        Future<String> future = productService.getResult();   //Async call to service method
        System.out.println("Current Thread Execution: " +Thread.currentThread().getName());    // Execute parallely and print this line immediately 
    
        ResponseDTO responseDTO = null;
        try {
            responseDTO = ResponseDTO.builder()
                    .status(HttpStatus.OK.toString())
                    .body(future.get()).build();   // current thread waits for result
    
             System.out.println("Thread freed : " +Thread.currentThread().getName());    // This line prints as soon as service tasks completes
            ResponseEntity responseEntity = ResponseEntity.ok(responseDTO);
            deferredResult.setResult(responseEntity);
        } catch (InterruptedException e) {
            System.out.println(e.getMessage());
        } catch (ExecutionException e) {
            System.out.println(e.getMessage());
        }
    
        return deferredResult;
    

    服务:

      @Async("threadPool")
    public Future<String> getResult() throws InterruptedException {
        System.out.println("Separate thread : "+Thread.currentThread().getName());
        Thread.sleep(6000);
        System.out.println("Separate thread Async task completed : "+Thread.currentThread().getName());
        return new AsyncResult<>("Success");
    }
    

    【讨论】:

    • 感谢回复。但是在服务方法的响应之前,控制器方法仍然没有释放。以下是我得到的回复。 Request received : http-nio-8080-exec-1 Current Thread Execution: http-nio-8080-exec-1 Separate thread : dnCallBackPool-1 Separate thread Async task completed : dnCallBackPool-1 Thread freed : http-nio-8080-exec-1 但是线程释放行不应该等待服务方法的响应。
    猜你喜欢
    • 1970-01-01
    • 2016-08-01
    • 1970-01-01
    • 2016-04-30
    • 2021-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多