Поток контроллера ожидает ответа метода Async - PullRequest
1 голос
/ 09 ноября 2019

Я новичок в весенней загрузке и хочу немного больше узнать о методах 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.

1 Ответ

0 голосов
/ 10 ноября 2019

Кажется, что метод контроллера ожидает ответа от метода обслуживания.

Да, метод контроллера ожидает ответа от productService, потому что @Asyncпоток из dnCallBackPool отвечает только за выполнение метода getResult() в productService.

Но код в блоке try-catch выполняется потоками веб-контейнера (например, http-nio-8080-exec-1)

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

Итак, Future object 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;

Служба:

  @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");
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...