0

The code below is for the fractal mandelbrot. It's work perfectly, but now I want to use the notion of thread on it. The result should be the same but the job must be doing by multiple Thread +10.

Here is my code:

import java.awt.Graphics;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;

public class test extends JFrame {

    private final int MAX_ITER = 570;
    private final double ZOOM = 150;
    private BufferedImage I;
    private double zx, zy, cX, cY, tmp;
    private static int x,y;

    public test() throws InterruptedException {
        super("Mandelbrot Set");
        setBounds(100, 100, 800, 600);
        setResizable(false);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        I = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
        for ( y = 0; y < getHeight(); y++) {

            for ( x = 0; x < getWidth(); x++) {
                Thread T = new Thread() {//*******
                    public void run() {

                          zx = zy = 0;
                          cX = (x - 400) / ZOOM;
                          cY = (y - 300) / ZOOM;
                          int iter = MAX_ITER;
                          while (zx * zx + zy * zy < 4 && iter > 0) {
                              tmp = zx * zx - zy * zy + cX;
                              zy = 2.0 * zx * zy + cY;
                              zx = tmp;
                              iter--;
                          }
                          I.setRGB(x, y, iter | (iter << 8));
                          System.out.println(Thread.currentThread().getId());
                    }

                };//*******

                T.start();//********
                T.join();//**********

            }
        }
    }

    @Override
    public void paint(Graphics g) {
        g.drawImage(I, 0, 0, this);
    }

    public static void main(String[] args) throws InterruptedException {
        new test().setVisible(true);
    }
}

I tried to instantiate thread in the loop for but I didn't get the result I want any suggestion?

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
Amine Choukri
  • 398
  • 2
  • 12

3 Answers3

1

You are calling T.join immediately after starting the thread. Thread#join blocks the current thread until that thread completes. This means that the computation will be happening on another thread, but you will get none of the benefits of parallelism as you won't start another thread until that one has finshed.

You could either start all the threads and wait for them all to finish together by using something like a CountDownLatch or try using the fork/join framework

ggovan
  • 1,907
  • 18
  • 21
0

Your code looks like it will compute the correct value but you need to draw the image after all the threads have completed to actually see the result. For now just call repaint at the end of the thread for the screen to refresh WxH times. To avoid unnecessary renders you could keep a global counter that increments upon entering the thread and decrements when exiting. When counter gets to 0 then repaint.

Fracdroid
  • 1,135
  • 10
  • 15
  • it works but it take more time tu show result there is any solution for that ? – Amine Choukri Jun 22 '18 at 22:28
  • Well, you are trying to use parallel computation to speed up algorithm which works when you have alot of CPUs to spread the work out on. I doubt you have 1000+ CPU. I would suggest trying to use the same number of threads as your computer has CPUs to see what results you get. – Fracdroid Jun 22 '18 at 22:39
  • The parts of your code are taking most time are the loops. Your algorithm has complexity of W x H x MAX_ITER. So lowering those values will result in noticeable speed up. Consider lowering the MAX_ITER variable to maybe 256 which is what I have used in past with fractals with success. Also the image looks like 700x500 pixels which is probably bigger then you need. Try doing a 256x256 on a bitmap then just scale it up into the rect you want. – Fracdroid Jun 22 '18 at 22:47
0

The first thing you want to do, is take the long process of the EDT. To do that use a SwingWorker:

import java.awt.Graphics;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.SwingWorker;

public class Test extends JFrame {//see https://www.javatpoint.com/java-naming-conventions

    private final int MAX_ITER = 570;
    private final double ZOOM = 150;
    private BufferedImage bImage;

    public Test() throws InterruptedException {
        super("Mandelbrot Set");
        setBounds(100, 100, 800, 600);
        setResizable(false);
        setDefaultCloseOperation(EXIT_ON_CLOSE);

        bImage = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
        new Draw().execute();
    }

    @Override
    public void paint(Graphics g) {
        g.drawImage(bImage, 0, 0, this);
    }

    public static void main(String[] args) throws InterruptedException {
        new Test().setVisible(true);
    }

    class Draw extends SwingWorker<Void, Void>{

        private double zx, zy, cX, cY, tmp;
        private int x,y;

        @Override
        protected Void doInBackground() throws Exception {

            for ( y = 0; y < getHeight(); y++) {
                for ( x = 0; x < getWidth(); x++) {
                    zx = zy = 0;
                    cX = (x - 400) / ZOOM;
                    cY = (y - 300) / ZOOM;
                    int iter = MAX_ITER;
                    while ((((zx * zx) + (zy * zy)) < 4) && (iter > 0)) {
                        tmp = ((zx * zx) - (zy * zy)) + cX;
                        zy = (2.0 * zx * zy) + cY;
                        zx = tmp;
                        iter--;
                    }

                    bImage.setRGB(x, y, iter | (iter << 8));
                }
                Thread.sleep(50); //added to slow down and demonstrate painting
                repaint();
            }
            return null;
        }
    }
}

Once you did, you can create multiple SwingWorkers to do the work. For example:

public class Test extends JFrame {//see https://www.javatpoint.com/java-naming-conventions

    private final int MAX_ITER = 570;
    private final double ZOOM = 150;
    private volatile BufferedImage bImage; 

    public Test() throws InterruptedException {
        super("Mandelbrot Set");
        setBounds(100, 100, 800, 600);
        setResizable(false);
        setDefaultCloseOperation(EXIT_ON_CLOSE);

        bImage = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);

        for (int y = 0; y < getHeight(); y++) {
            new Draw(y).execute();
        }
    }

    @Override
    public void paint(Graphics g) {
        g.drawImage(bImage, 0, 0, this);
    }

    public static void main(String[] args) throws InterruptedException {
        new Test().setVisible(true);
    }

    class Draw extends SwingWorker<Void, Void>{

        private double zx, zy, cX, cY, tmp;
        private int x,y;

        Draw(int y){
            this.y = y;
        }

        @Override
        protected Void doInBackground() throws Exception {

            for ( x = 0; x < getWidth(); x++) {
                zx = zy = 0;
                cX = (x - 400) / ZOOM;
                cY = (y - 300) / ZOOM;
                int iter = MAX_ITER;
                while ((((zx * zx) + (zy * zy)) < 4) && (iter > 0)) {
                    tmp = ((zx * zx) - (zy * zy)) + cX;
                    zy = (2.0 * zx * zy) + cY;
                    zx = tmp;
                    iter--;
                }
                bImage.setRGB(x, y, iter | (iter << 8));
            }
            Thread.sleep(50); //added to slow down and demonstrate painting
            repaint();

            return null;
        }
    }
}

(I am not sure if BufferedImage bImage need to be volatile. I hope someone can comment about it).

c0der
  • 18,467
  • 6
  • 33
  • 65