【问题标题】:How to use multiple thread to do a single job?如何使用多个线程来完成一项工作?
【发布时间】:2018-06-22 21:27:31
【问题描述】:

下面的代码用于分形曼德布罗。它工作得很好,但现在我想在它上面使用线程的概念。结果应该是一样的,但工作必须由多个线程+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);
    }
}

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

【问题讨论】:

  • 我没有看到与线程相关的代码,“我没有得到我想要的结果”不是问题。
  • 这是没有线程的基本代码......我说我试图在循环中添加线程但我失败了所以我正在寻找添加这个线程的正确方法
  • 向我们展示您如何尝试使用线程,也许我们可以告诉您您做错了什么。
  • 我为你们编辑了代码,就像你看到的那样,我将它添加到那里以在每次迭代时创建一个线程,但它并没有停止,它什么也没有显示
  • here关于join

标签: java multithreading swing


【解决方案1】:

您在启动线程后立即调用T.joinThread#join 阻塞当前线程,直到该线程完成。这意味着计算将在另一个线程上进行,但您不会获得并行性的任何好处,因为在另一个线程完成之前您不会启动另一个线程。

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

【讨论】:

    【解决方案2】:

    您要做的第一件事,就是完成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;
            }
        }
    }
    

    完成后,您可以创建多个SwingWorkers 来完成这项工作。例如:

    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。希望有人能对此发表评论)。

    【讨论】:

      【解决方案3】:

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

      【讨论】:

      • 它可以工作,但需要更多时间才能显示结果,有什么解决方案吗?
      • 嗯,您正在尝试使用并行计算来加速算法,当您有很多 CPU 来分散工作时,这种算法就可以工作。我怀疑你有 1000+ CPU。我建议尝试使用与您的计算机的 CPU 相同数量的线程来查看您得到的结果。
      • 代码中花费最多时间的部分是循环。您的算法的复杂度为 W x H x MAX_ITER。因此,降低这些值将导致明显的加速。考虑将 MAX_ITER 变量降低到 256,这是我过去成功使用的分形。此外,图像看起来像 700x500 像素,可能比您需要的更大。尝试在位图上制作 256x256,然后将其放大到您想要的矩形。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多