I have written a game of life for programming practice. There are 3 different implementations of the generator. First: One main thread + N sub threads, Second: SwingWorker + N sub threads, Third: SwingWorker + ExecutorService. N is the number of availableProcessors or user defined. The first two implementations runs fine, with one and more threads. The implementation with the ExecutorServise runs fine with one thread, but locks with more than one. I tried everything, but i can't get the solution.
Here the code of the fine workling implementation (second one):
package example.generator;
import javax.swing.SwingWorker;
/**
* AbstractGenerator implementation 2: SwingWorker + sub threads.
*
* @author Dima
*/
public final class WorldGenerator2 extends AbstractGenerator {
/**
* Constructor.
* @param gamePanel The game panel
*/
public WorldGenerator2() {
super();
}
/* (non-Javadoc)
* @see main.generator.AbstractGenerator#startGenerationProcess()
*/
@Override
protected void startGenerationProcess() {
final SwingWorker<Void, Void> worker = this.createWorker();
worker.execute();
}
/**
* Creates a swing worker for the generation process.
* @return The swing worker
*/
private SwingWorker<Void, Void> createWorker() {
return new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() throws InterruptedException {
WorldGenerator2.this.generationProcessing();
return null;
}
};
}
/* (non-Javadoc)
* @see main.generator.AbstractGenerator#startFirstStep()
*/
@Override
public void startFirstStep() throws InterruptedException {
this.getQueue().addAll(this.getLivingCells());
for (int i = 0; i < this.getCoresToUse(); i++) {
final Thread thread = new Thread() {
@Override
public void run() {
WorldGenerator2.this.fistStepProcessing();
}
};
thread.start();
thread.join();
}
}
/* (non-Javadoc)
* @see main.generator.AbstractGenerator#startSecondStep()
*/
@Override
protected void startSecondStep() throws InterruptedException {
this.getQueue().addAll(this.getCellsToCheck());
for (int i = 0; i < this.getCoresToUse(); i++) {
final Thread thread = new Thread() {
@Override
public void run() {
WorldGenerator2.this.secondStepProcessing();
}
};
thread.start();
thread.join();
}
}
}
Here is the code of the not working implementation with executor service:
package example.generator;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.swing.SwingWorker;
/**
* AbstractGenerator implementation 3: SwingWorker + ExecutorService.
*
* @author Dima
*/
public final class WorldGenerator3 extends AbstractGenerator {
private CountDownLatch countDownLatch;
private ExecutorService executor;
/**
* Constructor.
* @param gamePanel The game panel
*/
public WorldGenerator3() {
super();
}
/* (non-Javadoc)
* @see main.generator.AbstractGenerator#startGenerationProcess()
*/
@Override
protected void startGenerationProcess() {
this.executor = Executors.newFixedThreadPool(this.getCoresToUse());
final SwingWorker<Void, Void> worker = this.createWorker();
worker.execute();
}
/**
* Creates a swing worker for the generation process.
* @return The swing worker
*/
private SwingWorker<Void, Void> createWorker() {
return new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() throws InterruptedException {
WorldGenerator3.this.generationProcessing();
return null;
}
};
}
/* (non-Javadoc)
* @see main.generator.AbstractGenerator#startFirstStep()
*/
@Override
public void startFirstStep() throws InterruptedException {
this.getQueue().addAll(this.getLivingCells());
this.countDownLatch = new CountDownLatch(this.getCoresToUse());
for (int i = 0; i < this.getCoresToUse(); i++) {
this.executor.execute(new Runnable() {
@Override
public void run() {
WorldGenerator3.this.fistStepProcessing();
WorldGenerator3.this.countDownLatch.countDown();
}
});
}
this.countDownLatch.await();
}
/* (non-Javadoc)
* @see main.generator.AbstractGenerator#startSecondStep()
*/
@Override
protected void startSecondStep() throws InterruptedException {
this.getQueue().addAll(this.getCellsToCheck());
this.countDownLatch = new CountDownLatch(this.getCoresToUse());
for (int i = 0; i < this.getCoresToUse(); i++) {
this.executor.execute(new Runnable() {
@Override
public void run() {
WorldGenerator3.this.secondStepProcessing();
WorldGenerator3.this.countDownLatch.countDown();
}
});
}
this.countDownLatch.await();
}
}
Here you can download, a sample of my application, with a small launcher. it prints only the result of a iteration on the console: Link
Now my code looks like this:
/* (non-Javadoc)
* @see main.generator.AbstractGenerator#startFirstStep()
*/
@Override
public void startFirstStep() throws InterruptedException {
this.getQueue().addAll(this.getLivingCells());
final ArrayList<Callable<Void>> list = new ArrayList<Callable<Void>>(this.getCoresToUse());
for (int i = 0; i < this.getCoresToUse(); i++) {
list.add(new Callable<Void>() {
@Override
public Void call() throws Exception {
WorldGenerator3.this.fistStepProcessing();
return null;
}
}
);
}
this.executor.invokeAll(list);
}
But here is again the same problem. If I run it with one core (thread) there are no problems. If I set the number of cores to more than one, it locks. In my first question there is a link to a example, which you can run (in eclipse). Maybe I overlook something in the previous code.