Эти две задачи выполняются одновременно?

CompletableFuture<ResponseList> stsTask = CompletableFuture.supplyAsync(() -> this.stsCompute(question);
CompletableFuture<ResponseList> dssmTask = CompletableFuture.supplyAsync(() -> this.dssmCompute(question);

// Is this line unnecessary?
CompletableFuture<Void> twoFutures = CompletableFuture.allOf(stsTask, dssmTask);

try {
     ResponseList stsList = stsTask.get();
     ResponseList dssmList = dssmTask.get();

     // after the two are done, proceed here
     processResult(stsList, dssmList)
} catch(Exception e){
    // do something
}

У меня два вопроса:

  1. Эти две задачи выполняются одновременно? Или stsTask должен быть выполнен до dssmTask из-за метода get(), чтобы дождаться его завершения? Переменная twoFutures не используется.
  2. Линия CompletableFuture.allOf(stsTask, dssmTask) не нужна или нужна?

Похоже, вас не волнует возвращаемое значение processResult, тогда почему вы хотите использовать Get? Это заблокирует потоки. Здесь нет реального использования завершаемых фьючерсов. Также вместо get используйте join (), который также блокирует, но более чистый подход без попытки поймать. Я бы сказал allOf (). Join (). Run (() -> processResult)

Anvesh Vejandla 04.11.2018 14:22
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
1
88
3

Ответы 3

Если вы не вызываете get на twoFutures, эта строка является избыточной.

Если вы хотите подождать, пока они оба закончатся, а затем что-то сделать с результатами, вам следует реорганизовать свой код следующим образом:

stsTask.thenAcceptBoth(dssmTask, (stsResult, dssmResult) -> {
    ResponseList stsList = stsResult; // or stsTask.get()
    ResponseList dssmList = dssmResult; // or dssmTask.get()
    // ...     
});

Я хочу, чтобы stsTask и dssmTask выполнялись одновременно, чтобы ускориться. Это основная цель.

user697911 04.11.2018 19:10

используйте регистратор, если вы не уверены в пути выполнения многопоточной задачи:

    private static Logger logger = getLogger(S.class);

    public static void main(String[] args) {


        CompletableFuture<List> stsTask = CompletableFuture.supplyAsync(() -> {
            logger.info("running");
            return new ArrayList();
        });
        CompletableFuture<List> dssmTask = CompletableFuture.supplyAsync(() -> {
            logger.info("running");
            return new ArrayList();
        });

        // Is this line unnecessary?
        CompletableFuture<Void> twoFutures = CompletableFuture.allOf(stsTask, dssmTask);

        logger.info("twoFutures is completed? " + twoFutures.isDone());
        logger.info("allof dose not wait task to complete, just to check if all the task is completed, so this is unnecessary");


        try {
            List stsList = stsTask.get();
            logger.info("stsList completed? " + stsTask.isDone());
            List dssmList = dssmTask.get();
            logger.info("dssmList completed? " + dssmTask.isDone());

            logger.info("get() will block until task is done");

            // after the two are done, proceed here
//          processResult(stsList, dssmList)
        } catch (Exception e) {
            // do something
        }







    }

выход:

15:18:28.791 [main] INFO cn.lihongjie.S - twoFutures is completed? false
15:18:28.791 [ForkJoinPool.commonPool-worker-2] INFO cn.lihongjie.S - running
15:18:28.791 [ForkJoinPool.commonPool-worker-1] INFO cn.lihongjie.S - running
15:18:28.794 [main] INFO cn.lihongjie.S - allof dose not wait task to complete, just to check if all the task is completed, so this is unnecessary
15:18:28.795 [main] INFO cn.lihongjie.S - stsList completed? true
15:18:28.795 [main] INFO cn.lihongjie.S - dssmList completed? true
15:18:28.795 [main] INFO cn.lihongjie.S - get will block until task is done

Я использую logback logger, по умолчанию он выводит имя потока, что удобно для этого вопроса.

  1. задача выполняется одновременно, ее запускают два потока 15:18:28.791 [ForkJoinPool.commonPool-worker-2] INFO cn.lihongjie.S - running 15:18:28.791 [ForkJoinPool.commonPool-worker-1] INFO cn.lihongjie.S - running

  2. allOf не нужен, этот вызов не блокируется, пока все задачи не будут выполнены. Вы можете выяснить это, посмотрев журнал.

Значит, они действительно выполняются одновременно? так что мне не нужно вносить какие-либо изменения

user697911 04.11.2018 19:13

@ user697911 да

宏杰李 05.11.2018 02:05

Да, они выполняются одновременно, если у вас достаточно потоков в общем пуле вилки / соединения. Метод allOf возвращает новый CompletableFuture, который завершается, когда завершаются все данные CompletableFutures. Но у вас нет возможности объединить результат, поэтому здесь он не нужен.

Еще один момент, который следует учитывать, - это вызов метода future.get() для получения результата. Вызов этого метода является блокирующим и будет держать ваш вызывающий поток в состоянии блокировки.

Итак, вот лучший способ сделать это,

stsTask.thenCombine(dssmTask, (stsList, dssmList) -> processResult(stsList, dssmList));

Другие вопросы по теме