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

时间:2018-06-22 21:27:31

标签: java multithreading swing

下面的代码用于分形曼德博。它工作得很好,但是现在我想在其上使用线程的概念。结果应该相同,但是该工作必须由多个线程+10完成。

这是我的代码:

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);
    }
}

我尝试实例化循环中的线程,但没有得到想要的结果 有什么建议吗?

3 个答案:

答案 0 :(得分:1)

启动线程后,您正在立即调用T.joinThread#join阻止当前线程,直到该线程完成。这意味着计算将在另一个线程上进行,但是您将无法获得并行性的好处,因为只有在该线程结束后才启动另一个线程。

您可以使用CountDownLatch之类的东西来启动所有线程并等待它们一起完成,或者尝试使用fork/join framework

答案 1 :(得分:0)

您的代码看起来将计算出正确的值,但是您需要在所有线程完成后绘制图像才能实际看到结果。现在,只需在线程末尾调用repaint即可刷新屏幕WxH时间。为避免不必要的渲染,您可以保留一个全局计数器,该计数器在进入线程时增加,而在退出线程时减少。当计数器变为0时,重新粉刷。

答案 2 :(得分:0)

您要做的第一件事就是花费EDT的漫长过程。为此,请使用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;
        }
    }
}

完成后,您可以创建多个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 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;
        }
    }
}

(我不确定BufferedImage bImage是否需要volatile。我希望有人对此发表评论。)