简体   繁体   中英

Wait for the first thread to finish before running other threads in parallel

From my main flow I want to do some tasks in parallel. Say I have 4 tasks that I want to execute in a separate flow, but in those 4 tasks, 1st task needs to be completed before I can run other tasks in parallel.

I thinks my code works as per my requirement, but is there a better approach?

public static void main(String[] args) {
        System.out.println("In main");

        ExecutorService executor = Executors.newSingleThreadExecutor();

        executor.submit(() -> {
            runParalleltasks();
        });

        executor.shutdown();
        System.out.println("Exiting main");
    }

    private static void runParalleltasks() {
        System.out.println("Running parallel tasks");
        doTask1();
        ExecutorService executor = Executors.newFixedThreadPool(3);
        executor.submit(() -> {
            doTask2();
        });
        executor.submit(() -> {
            doTask3();
                });
        executor.submit(() -> {
            doTask4();
        });

        executor.shutdown();
        System.out.println("Exiting parallel tasks");
    }

You might want to take a look at the new CompletableFuture facility. It might not provide a lot of help with a trivial case such as yours but it offers a lot of flexibility:

import static java.util.concurrent.CompletableFuture.allOf;
import static java.util.concurrent.CompletableFuture.runAsync;

runAsync(() -> doTask1(), executor)
        .thenCompose(v -> allOf(
                runAsync(() -> doTask2(), executor),
                runAsync(() -> doTask3(), executor),
                runAsync(() -> doTask4(), executor)
        ));

Where this approach would really shine you is if you needed to pass output of task1 to the dependent tasks. Suppose that doTask1 returns a String and doTask2 accepts a String . Now instead of runAsync for the first task we should use supplyAsync :

supplyAsync(() -> doTask1(), executor)
        .thenCompose(resultOf1 -> allOf(
                runAsync(() -> doTask2(resultOf1), executor),
                runAsync(() -> doTask3(), executor),
                runAsync(() -> doTask4(), executor)
        ));

You can do this with an ExecutorService as well, much like your original approach. All you have to do is to use the result of submit which allows subsequent tasks to wait for its completion:

ExecutorService executor = Executors.newFixedThreadPool(4);
Future<?> task1 = executor.submit(() -> doTask1());
Stream.<Runnable>of(() -> doTask2(), () -> doTask3(), () -> doTask4())
      .forEach(r -> executor.submit(() -> { try {
              task1.get();
              r.run();
          } catch(InterruptedException|ExecutionException ex){}
      }));
executor.shutdown();

We have to catch exceptions when waiting for the completion of the first task, but this also opens the opportunity to deliberately skip the next task if the first task fails or gets canceled. Since normally, the dependency between tasks exists because the subsequent tasks need the result of the first task, waiting via get() is the natural way. As soon as doTask1() returns a value, the submit invocation above will use submit(Callable) rather than submit(Runnable) and the returned Future will have a generic type reflecting the return type of the method, so the result can be retrieved via its get() method.

In order to avoid deadlocks, it least one of the following conditions must be true:

  • there are enough threads for all submitted tasks, or
  • the queue's retrieval order is identical to the submission order

In the example, even both apply.

Note that the stream use above is not necessary, a classical loop could do that as well:

for(Runnable r: Arrays.<Runnable>asList(() -> doTask2(), () -> doTask3(), () -> doTask4()))
    executor.submit(() -> { try {
            task1.get();
            r.run();
        } catch(InterruptedException|ExecutionException ex){}
    });

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM