The program is a Mandelbrot set renderer, and it opens initially with a correctly calculated and rendered image; this initialization is done with my recalculate()
method. However, when my event handler makes a call to the recalculate()
method, I think it is skipping everything that is in a different thread (i.e. it still produces console output, but the heavy calculation is not done).
The reason I think this is that the console output shows the time for the initial calculation to be usually about 1500~1800 ms, but any further calls to recalculate()
comes back with a time of about < 15 ms, and the GUI is updated to just a solid color.
Console output
Working...
Done.
Took 1711 ms.
<event handler calls recalculate()>
Working...
Done.
Took 16 ms.
Recalculate()
public static void recalculate(double x1, double y1, double x2, double y2, int[][] iterCounter){
MandelbrotTask[] tasks=new MandelbrotTask[4];
tasks[0]=new MandelbrotTask(maxIters, x1, y1, x2, y2, 0, WIDTH, 0, HEIGHT/4, iterCounter);
tasks[1]=new MandelbrotTask(maxIters, x1, y1, x2, y2, 0, WIDTH, HEIGHT/4, 2*(HEIGHT/4), iterCounter);
tasks[2]=new MandelbrotTask(maxIters, x1, y1, x2, y2, 0, WIDTH, 2*(HEIGHT/4), 3*(HEIGHT/4), iterCounter);
tasks[3]=new MandelbrotTask(maxIters, x1, y1, x2, y2, 0, WIDTH, 3*(HEIGHT/4), 4*(HEIGHT/4), iterCounter);
//parallelize computation
Thread[] threads=new Thread[4];
for(int i=0; i<4; i++){
threads[i]=new Thread(tasks[i]);
}
System.out.println("Working...");
//start timer, start computation
long start=System.currentTimeMillis();
for(int i=0; i<4; i++){
threads[i].start();
}
for(int i=0; i<4; i++){
try {
threads[i].join();
} catch (InterruptedException e) {
System.err.println("A thread was interrupted.");
}
}
//end timer
long end=System.currentTimeMillis();
long elapsed=end-start;
System.out.println("Done.");
System.out.println("Took " + elapsed + " ms.");
}
Event handler that calls recalculate()
protected static void handleMouseReleased(MouseEvent e) {
recalculate(zoomBox.getX(), zoomBox.getY(), zoomBox.getX()+zoomBox.getWidth(), zoomBox.getY()+zoomBox.getHeight(), iterCounts);
SwingUtilities.invokeLater(new Runnable(){
@Override
public void run() {
zoomBox=null;
bufferedImage=render(iterCounts, bufferedImage, zoomBox);
ImageIcon icon=new ImageIcon(bufferedImage);
content.setIcon(icon);
}
});
}
MandelbrotTask class
public class MandelbrotTask implements Runnable {
private double x1, y1, x2, y2;
private int startCol, endCol, startRow, endRow, maxIters;
private int[][] iterCounts;
public MandelbrotTask(int maxIters, double x1, double y1, double x2, double y2, int startCol, int endCol, int startRow, int endRow, int[][] iterCounts) {
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
this.startCol = startCol;
this.endCol = endCol;
this.startRow = startRow;
this.endRow = endRow;
this.iterCounts = iterCounts;
this.maxIters=maxIters;
}
@Override
public void run() {
for (int i = startRow; i < endRow; i++) {
for (int j = startCol; j < endCol; j++) {
Complex c = getComplex(i, j);
int iterCount = countIters(c);
iterCounts[i][j] = iterCount;
}
}
}
public Complex getComplex(int i, int j){
//output image is 600 X 600 pixels
double incrementX;
double incrementY;
if(x2!=x1){
incrementX=(Math.abs(x2-x1)/600);
}
else{
throw new ArithmeticException("Error: area=0");
}
if(y2!=y1){
incrementY=(Math.abs(y2-y1)/600);
}
else{
throw new ArithmeticException("Error: area=0");
}
return new Complex(x1+((double)i*incrementX), y1+((double)j*incrementY));
}
public int countIters(Complex c){
Complex z=new Complex(0, 0);
int iters=0;
while(z.getMagnitude()<2 && iters<=maxIters){
z=z.multiply(z).add(c);
iters++;
}
return iters;
}
}