控制器线程正在等待异步方法响应

时间:2019-11-09 17:02:25

标签: java spring spring-boot

我是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

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

1 个答案:

答案 0 :(得分:0)

  

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

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

但是productService块中的代码是由Web容器线程(例如try-catch)执行的

http-nio-8080-exec-1

responseDTO = ResponseDTO.builder() .status(HttpStatus.OK.toString()) .body(productService.getResult()**.get()**).build(); 上的Future对象get()调用是阻塞调用,当前线程应等待productService.getResult()线程完成处理并返回结果

  

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

在控制器方法末尾的@Async对象上的get()上也是如此,这样两个方法都可以并行执行,下面是一个示例

控制器:

Future

服务:

 @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;