package org.openpixi.pixi.parallel.particleaccess;
import org.openpixi.pixi.physics.particles.Particle;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
/**
* Executes action upon particles in parallel using threads.
*
* Why do we use Callable interface instead of Runnable?
* - Because we want to use the invokeAll() method of ExecutorService.
* Why do we want to use the invokeAll() method and not the execute() or submit() method?
* - Because execute() and submit() do not wait for the tasks to finish.
*/
public class ParallelParticleIterator implements ParticleIterator {
/* These are exposed here for inner classes
since they can to be passed to them as method arguments */
private ParticleAction action;
private List<Particle> particles;
private List<Callable<Object>> tasks = new ArrayList<Callable<Object>>();
private ExecutorService threadExecutor;
public ParallelParticleIterator(int numOfThreads, ExecutorService threadExecutor) {
this.threadExecutor = threadExecutor;
for (int i = 0; i < numOfThreads; ++i) {
tasks.add(new Task(i, numOfThreads));
}
}
public void execute(List<Particle> particles, ParticleAction action) {
this.action = action;
this.particles = particles;
try {
threadExecutor.invokeAll(tasks);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
private class Task implements Callable<Object> {
private int threadIdx;
private int numOfThreads;
private Task(int threadIdx, int numOfThreads) {
this.threadIdx = threadIdx;
this.numOfThreads = numOfThreads;
}
public Object call() throws Exception {
for (int particleIdx = threadIdx; particleIdx < particles.size(); particleIdx += numOfThreads) {
action.execute(particles.get(particleIdx));
}
return null;
}
}
}