0

Is there a easy way to parallelise a foreach loop in java 8 using some library stuff?

void someFunction(SomeType stuff, SomeType andStuff) {
    for (Object object : lotsOfObjects)
        object.doSomethingThatCanBeDoneInParallel(stuff, andStuff);
}

Multithreading is kinda painful and time consuming so i wonder if there is a simpler way to do the above using some library.

thanks.

edited in 3/06/2018

ExecutorServices is very handy indeed, I can't use shutdown() to wait because I run the thing every frame and create a new ExecutorServices every frame would be too expensive.

I ended up writing a class to parallelize a fori loop and I thought I share it with other newbies like me.

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;

public class ParallelForI {
    public ParallelForI(int numberOfThread) {
        NUMBER_OF_THREAD = numberOfThread;
        executorService = Executors.newFixedThreadPool(NUMBER_OF_THREAD);
        finished = new AtomicBoolean[NUMBER_OF_THREAD];
        for (int i = 0; i < finished.length; i++)
            finished[i] = new AtomicBoolean(true);
        // true is better for waitForLastRun before any run.
    }
    private ExecutorService executorService;
    private final int NUMBER_OF_THREAD;

    private AtomicBoolean[] finished;
    public void waitForLastRun() {
        synchronized (this) {
        /* synchronized outside the loop so other thread
         can't notify when it's not waiting. */
            for (int i = 0; i < NUMBER_OF_THREAD; i++) {
                if (!finished[i].get()) {
                    i = -1;
                    try {
                        this.wait(); //
                    } catch (InterruptedException e) {
                        // do nothing and move one.
                    }
                }
            }
        }
    }

    public void run(FunctionForI functionForI, final int MAX_I) {
        for (AtomicBoolean finished : finished)
            finished.set(false); // just started
        for (int i = 0; i < NUMBER_OF_THREAD; i++) {
            final int threadNumber = i;
            executorService.submit(new Runnable() {
                @Override // use lambda if you have java 8 or above
                public void run() {
                    int iInitial = threadNumber * MAX_I / NUMBER_OF_THREAD;
                    int iSmallerThan;
                    if (threadNumber == NUMBER_OF_THREAD - 1) // last thread
                        iSmallerThan = MAX_I;
                    else
                        iSmallerThan = (threadNumber + 1) * MAX_I / NUMBER_OF_THREAD;
                    for (int i1 = iInitial; i1 < iSmallerThan; i1++) {
                        functionForI.run(i1);
                    }
                    finished[threadNumber].set(true);
                    synchronized (this) {
                        this.notify();
                    }
                }
            });
        }
    }

    public interface FunctionForI {
        void run(int i);
    }
}

And this is the way to use it:

void someFunction(final SomeType stuff, final SomeType andStuff) {
    ParallelForI parallelForI = new parallelForI(numberOfThread);
    // swap numberOfThread with a suitable int

    parallelForI.run(new ParallelForI.FunctionForI() {
        @Override // use lambda if you have java 8 or above
        public void run(int i) {
            lotsOfObjects[i].doSomethingThatCanBeDoneInParallel(stuff, andStuff);
            // don't have to be array.
        }
    }, lotsOfObjects.length); // again, don't have to be array

    parallellForI.waitForLastRun(); // put this where ever you want 
    // You can even put this before parallelForI.run().
    // Although it doesn't make sense to do that...
    // Unlike shutdown() waitForLastRun() will not cause parallelForI to reject future task.
}
Shuang Li
  • 75
  • 1
  • 9

3 Answers3

2

A solution could be to launch every task in a Thread as follows:

new Thread(() -> object.doSomethingThatCanBeDoneInParallel(stuff, andStuff)).start();

but this is not a relevant solution as Thread creation is costly, so there are mechanisms and tools to help you: the Executors class to build some pools.

Once you have the instance that will manage this, you provide it with tasks, which will run in parallel, on the number of threads you choose:

void someFunction(SomeType stuff, SomeType andStuff) {
    ExecutorService exe = Executors.newFixedThreadPool(4);   // 4 can be changed of course
    for (Object object : lotsOfObjects) {
        exe.submit(() -> object.doSomethingThatCanBeDoneInParallel(stuff, andStuff));
    }

    // Following lines are optional, depending if you need to wait until all tasks are finished or not
    exe.shutdown();
    try {
        exe.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }   
}
k_ssb
  • 6,024
  • 23
  • 47
azro
  • 53,056
  • 7
  • 34
  • 70
1

Use parallel streams. But this is not an universal solution.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
Oleg Cherednik
  • 17,377
  • 4
  • 21
  • 35
0

For loops in java are inherently serial. There is no way to do such thing with them. With the introduction of streams though, you can parallelize the operations on a collection using them.

NiVeR
  • 9,644
  • 4
  • 30
  • 35