Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Execute a for loop in parallel using CompletableFuture in Java and log the execution

I have a for loop which I am trying to parallelize using CompletableFuture.

for (int i = 0; i < 10000; i++) {
    doSomething();
    doSomethingElse();
}

What I have till now is:

for (int i = 0; i < 10000; i++) {
    CompletableFuture.runAsync(() -> doSomething());
    CompletableFuture.runAsync(() -> doSomethingElse());
}

I guess this serves the purpose but there is a requirement to print log just before the start and end of all the processing. If I do this:

log("Started doing things");
for (int i = 0; i < 10000; i++) {
    CompletableFuture.runAsync(() -> doSomething());
    CompletableFuture.runAsync(() -> doSomethingElse());
}
log("Ended doing things");

Does this guarantee that the second log statement will be printed once all the for loop is over since that is executing in a separate thread? If not, is there a way to do this without blocking the main thread?

like image 423
mohitmayank Avatar asked Nov 18 '18 11:11

mohitmayank


1 Answers

I suppose CompletableFuture is the wrong concept for your needs. If you want to execute an arbitrary number of similar tasks in parallel, the easiest thing is to use the method invokeAll(...) on an ExecutionService:

// First, create a list with all tasks you want to execute in parallel
List<Callable<?>> tasks = new ArrayList<>(10000);
for (int i = 0; i < 10000; ++i) {
    // we need to create Callables, so if your doSomething method returns void, we have to convert it to a Callable using helper method from class Executors
    tasks.add(Executors.callable(this::doSomething));
}

// Then, create an executor service that can execute these tasks
// There are different executors you can choose from, I take one that has a fixed pool of threads
ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

// Last but not least, call invokeAll to execute all tasks and wait for them to complete
executorService.invokeAll(tasks);

// This method will be called when all tasks have been completed successfully:
System.out.println("done");
like image 154
isnot2bad Avatar answered Oct 12 '22 19:10

isnot2bad