简体   繁体   English

如何使用多线程完成一项工作?

[英]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. 结果应该是相同的,但是工作必须由多个线程+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. 您在启动线程后立即调用T.join Thread#join blocks the current thread until that thread completes. Thread#join阻塞当前线程,直到该线程完成。 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 您可以使用CountDownLatch类的方法来启动所有线程并等待它们一起完成,或者尝试使用fork / join框架

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. 现在,只需在线程末尾调用repaint即可刷新屏幕WxH时间。 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. 当计数器变为0时,重新粉刷。

The first thing you want to do, is take the long process of the EDT . 您要做的第一件事就是花费漫长的EDT过程。 To do that use a SwingWorker : 为此,请使用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. 完成后,您可以创建多个SwingWorker来完成工作。 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). (我不确定BufferedImage bImage是否需要volatile 。希望有人对此发表评论)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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