Эти две задачи выполняются одновременно? - PullRequest
0 голосов
/ 04 ноября 2018
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) ненужной или необходимой?

Ответы [ 3 ]

0 голосов
/ 04 ноября 2018

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

    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 не требуется, этот вызов не блокируется, пока все задачи не будут выполнены. Вы можете выяснить, посмотрев на журнал.

0 голосов
/ 06 ноября 2018

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

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

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

stsTask.thenCombine(dssmTask, (stsList, dssmList) -> processResult(stsList, dssmList));
0 голосов
/ 04 ноября 2018

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

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

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