Синхронное поведение при использовании методов Java CompletableFuture

Я использую Java CompletableFuture в весенней загрузке @Service:

@Service
public class ProcessService {

    private static final ExecutorService EXECUTOR = Executors.newFixedThreadPool(3);

    @Autowired
    ChangeHistoryService changeHistoryService;

    public Attribute process(Attribute attribute) {
        //some code

        CompletableFuture.runAsync(() -> changeHistoryService.logChanges(attribute), EXECUTOR);

        return attribute;
    }

}

Метод process вызывается из метода внутри @RestController:

@RestController
public class ProcessController {


    @Autowired
    ProcessService processService;

    @RequestMapping(value = "/processAttribute",
            method = {RequestMethod.POST},
            produces = {MediaType.APPLICATION_JSON_VALUE},
            consumes = {MediaType.APPLICATION_JSON_VALUE})
    public Attribute applyRules(@RequestBody Attribute attribute) {

        Attribute resultValue = processService.service(attribute);

        return resultValue;
    }

}

ChangeHistoryService::logChanges сохранять только некоторые данные в базе данных в соответствии с ее параметром. У меня есть микросервис, который делает несколько запросов к этой конечной точке «/ processAttribute» и распечатывает все ответы.

Когда я помещаю точку останова в метод logChanges, микросервис ожидает некоторого запроса, но не всех, что заставляет меня думать, что ChangeHistoryService::logChanges не всегда работает асинхронно. Если я не предоставлю runAsync ExecutorService, микросервис будет блокироваться по большему количеству запросов, но все же не по всем. Насколько я понял, это связано с тем, что метод, обрабатывающий запрос, и метод logChanges используют один и тот же пул потоков (ForkJoinPool?). В любом случае, поскольку у меня есть другой ExecutorService, logChanges не должен работать независимо? Или что-то о том, как IDE обрабатывает точки останова в асинхронной задаче? Я использую IntelliJ IDEA.


person Jorj    schedule 15.01.2018    source источник


Ответы (2)


Проблема заключалась в том, что точка останова приостанавливала все потоки, а не только поток, выполняющий logChanges метод. Я исправляю это в Intellij IDEA, щелкнув правой кнопкой мыши по точке останова и установив флажок «Тема», а не «Все»:

введите описание изображения здесь

person Jorj    schedule 15.01.2018

У вас довольно маленький пул с нитками, поэтому неудивительно, что вы можете насытить его. Потоки, обрабатывающие запросы, не совпадают с потоками, обрабатывающими ваш CompletableFutures. Один из них является внутренним компонентом сервера, а второй - явно созданным вами EXECUTOR.

Если вы хотите увеличить асинхронность, попробуйте добавить EXECUTOR еще несколько потоков и посмотрите, как поведение изменится соответственно. В настоящее время EXECUTOR является узким местом, поскольку для выполнения запросов доступно гораздо больше потоков.

Обратите внимание, что, помещая точку останова внутри logChanges(), вы блокируете один поток в пуле, делая его еще более насыщенным.

person Kayaman    schedule 15.01.2018
comment
Привет @Kayaman! Из документации Executors.newFixedThreadPool: ›Если дополнительные задачи отправляются, когда все потоки активны, они будут ждать в очереди, пока поток не станет доступным. Я не понимаю, почему поток, отправивший задачу, блокируется, даже если пул потоков переполнен. Задача должна быть добавлена ​​в очередь, поток отправителя продолжит работу, и задача будет обработана независимо, когда станет доступным потоком. если у меня небольшой пул потоков, очередь будет продолжать расти, но не блокирует поток отправителя. Это не то, что должно быть? - person Jorj; 15.01.2018
comment
Код выше вашего фактического кода? Вы не делаете ничего глупого, чтобы предотвратить выполнение потока запросов, не так ли? - person Kayaman; 15.01.2018
comment
Мой реальный код, поэтому я думаю, что не делаю ничего глупого, чтобы предотвратить выполнение потока запроса - person Jorj; 15.01.2018
comment
Вы пробовали использовать @Async на logChanges()? Как вы на самом деле определяете, что он не работает асинхронно? Какой трафик вы отправляете на сервер? - person Kayaman; 15.01.2018