简体   繁体   中英

How to use multiple thread to do a single job?

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?

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

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.

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 SwingWorker s 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).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM