0

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;
    }
}
Mat Jones
  • 936
  • 1
  • 10
  • 27
  • What does `MandelbrotTask` do? Also, it might be better to use a `ExecutorService`, but you should be ware, that in blocking the Event Dispatching Thread, you are preventing the UI from been updated until after the `recalculate` method (essentially) returns – MadProgrammer Nov 23 '15 at 02:16
  • I am not sure where to begin... There's obviously a lot going on, but without knowing how the threads interact, it's really hard to say anything useful. A couple of things come to mind though: `iterCounts` is not a primitive type, so data in there that needs to be shared between threads needs to use some sort of synchronization/memory barrier. Also, I am puzzled by the statement `zoomBox=null;` in the `handleMouseReleased`method. When does `zoomBox` get reset with a valid object? Moreover, if zoomBox isn't declared `volatile`, there is no hard guarantee that other threads will see the update. – Daniel Nov 25 '15 at 09:26

0 Answers0