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.
}
解决方案
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();
}
}