4

I must iterate over an list and call for every object a method, but in parallel. After the loop, there other statements, which must wait for the parallel method invocations. How can I do that in JAVA?

public void a(List<Object> list) {
    for(Object o : list) {
        asynchMethod(o); // this n method call must run in the same time
    }

    // wait for all asynchMethod result
    /**
     * ...other statements
     */
}

private void asynchMethod(Object o) {
    // some code
}
Károly Neue
  • 89
  • 2
  • 9

3 Answers3

8

I see that you are using java 8, you can then use the parallelStream approach:

public void a(List<Object> list) {
    list.parallelStream().forEach(s -> asyncMethod(o));
}

which must wait for the parallel method invocations

The foreach is a terminal operation aka it will wait to be finished until moving forward to the next code line: Java parallel stream: how to wait for threads for a parallel stream to finish?

If you want some more information about parallelStream: https://docs.oracle.com/javase/tutorial/collections/streams/parallelism.html#executing_streams_in_parallel

If you want to know how many threads parallelstream uses: How many threads are spawned in parallelStream in Java 8?

Watch out with using threads and pararellStream, they come with their own heap of problems. Before using them you should always carefully examine the situation and see if they are worth the trouble they can possible bring: Should I always use a parallel stream when possible?

bramdc
  • 580
  • 1
  • 5
  • 21
  • the methods doesn't run in parallell, in sequence on the same thread – Károly Neue Feb 14 '20 at 11:05
  • 1
    @KárolyNeue: the `Stream::parallelStream` method will use the invoking `Thread`. If there are lots of items in the `List`, it will _also_ use other `Thread`s (from the fork-join-pool). It may well end up running them all sequentially on the invoking `Thread` if it believes that context switching to other `Thread`s will not save time for the specific `List` being streamed. – BeUndead Feb 14 '20 at 11:26
  • 1
    @KárolyNeue have a looks at this SO question: https://stackoverflow.com/questions/30802463/how-many-threads-are-spawned-in-parallelstream-in-java-8 – bramdc Feb 14 '20 at 11:27
  • thanks, that works. But the asyncMethod and the a method are in the same EJB bean, and when I call the asynchMethod, than get a NullPointerException for the entityManager. Can you help me, how to resolve it? – Károly Neue Feb 14 '20 at 13:20
  • @KárolyNeue I will be glad to help, but need more information. Maybe it's best to create another question on StackOverflow if you can't find a solution to your problem. – bramdc Feb 14 '20 at 14:43
  • @bramdc I have created a new question: https://stackoverflow.com/questions/60259421/entitymanager-is-null-when-use-in-parallelstream thanks – Károly Neue Feb 17 '20 at 09:47
1

One fool proof way (out of many) to execute any method in parallel is to start a thread pool and then assign tasks to it and wait for the tasks to finish.

public static ThreadPoolExecutor getExecutorService(int poolSize, int maxPoolSize{
  int threadPoolshutDownTime = 10L;
  ThreadPoolExecutor executorService= new ThreadPoolExecutor(poolSize, maxPoolSize, threadPoolshutDownTime, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
  executorService.allowCoreThreadTimeOut(true); // allows the threadpool to shutdown if no task is assigned
  return executorService;
}

Now call this inside your method like the following :

public void a(List<Object> list) throws InterruptedException, ExecutionException  {

  List<Callable<Boolean>> callables = new ArrayList<>(list.size());
  list.forEach(object ->callables.add(() -> return asynchMethod(object)));

  for (Future<Boolean> booleanFuture : this.getExecutorService(1,4).invokeAll(callables)) {
            booleanFuture.get(); //this will wait for the callables to be done!
  }
}

Also modify your aysncMethod as the following :

private boolean asynchMethod(Object o) {
    return o.doMagic(); //doMagic returns a boolean when completed
}
papaya
  • 1,505
  • 1
  • 13
  • 26
0

Use CompletableFuture.

CompletableFuture.allOf(list.stream()
  .map(i -> CompletableFuture.submit(o -> asyncMethod(I))
  .toArray())) 
     .join();
daniu
  • 14,137
  • 4
  • 32
  • 53