多线程Java

3

我正在尝试在我的 Java Mandelbrot 应用程序中实现多线程:

目前为止,这是我的实现:

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;

public class MandelbrotSet {
   private int numberOfIterations;
   private double realMin;
   private double realMax;
   private double imaginaryMin;
   private double imaginaryMax;
   private int width;
   private int height;
   public BufferedImage image;
   public Graphics2D imageGraphics;

   public MandelbrotSet() {
      // Set the width and the height
      this.width = 600;
      this.height = 400;
      image = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);
      imageGraphics = image.createGraphics();
                this.realMin = -2.0;
      this.realMax = 1;
      this.imaginaryMin = -1;
      this.imaginaryMax = 1;
      this.numberOfIterations = 1000;
   }

   public Complex calculateComplexNumber(int x, int y) {
      double realPart = realMin + x * (realMax - realMin) / (this.getWidth() - 1);
      double imaginaryPart = imaginaryMax - y * (imaginaryMax - imaginaryMin) / (this.getHeight() - 1);

      return new Complex(realPart, imaginaryPart);
   }

   public void calculateMandelbrotImagePoints() {
      Thread[] threads = new Thread[4];

      for (int i = 0; i < maxThreads; i++) {
         threads[i] = new Thread(new MThread(i));
         threads[i].start();
      }
   }

   class MThread implements Runnable {
      private int i;

      public MThread(int i) {
         this.i = i;
      }

      //Method uses the thread number to draw the mandelbrot in columns
      public void run() {
         for (int x = i; x < width; x += 4) {
            for (int y = 0; y < height; y++) {
               int n = 0;
               Complex c = calculateComplexNumber(x, y);
               Complex z = c;

               while ((zNumber.modulusSquared() < 4.0D) && (n < numberOfIterations)) {
                  z = z.square();
                  z.add(c);
                  n++;
               }

               if (n == numberOfIterations) {
                  imageGraphics.setColor(Color.BLACK);
               } else {
                  imageGraphics.setColor(Color.getHSBColor(n / 100.0F, 1, 1));
               }
               imageGraphics.drawLine(x,y,x,y);
            }
         }
      }
   }
}

发生的问题是在绘制图像时,图像中显示了不正确的像素: http://i.stack.imgur.com/wq2TN.png 当我使用类似以下的线程进行检查时:
threads[i].isAlive();

图片似乎成功显示了,但是渲染这个图片需要的时间更长(多达3倍)。

我有两个疑问:

  1. 我做错了什么?

  2. 对于大量迭代(>1000),绘制曼德布洛特集到 BufferedImage 的最佳方式是什么?

4个回答

4

图形绘制不是线程安全的,因此无法从多个线程向同一{屏幕、图像、其他}进行绘制。在以下行之间,您的线程可能会被中断(即可能发生上下文切换):

                  imageGraphics.setColor(Color.getHSBColor(n / 100.0F, 1, 1));
               }
               imageGraphics.drawLine(x,y,x,y);

一个选择是为每个线程提供自己的图像(比如,图像的四分之一作为平铺),然后在结束时将这些图像合并。


2

我希望这就是@Michael Chang所建议的。我已经调整了代码以呈现出色带。

请注意,我无法测试此代码。我不熟悉Java图形。

                                                                                           import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;

public class MandelbrotSet {
  private int numberOfIterations;
  private double realMin;
  private double realMax;
  private double imaginaryMin;
  private double imaginaryMax;
  private int width;
  private int height;
  public BufferedImage image;
  public Graphics2D imageGraphics;
  static final int nThreads = 4;

  public MandelbrotSet(int width, int height) {
    // Set the width and the height
    this.width = width;
    this.height = height;
    image = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);
    imageGraphics = image.createGraphics();
    this.realMin = -2.0;
    this.realMax = 1;
    this.imaginaryMin = -1;
    this.imaginaryMax = 1;
    this.numberOfIterations = 1000;
  }

  public Complex calculateComplexNumber(int x, int y) {
    double realPart = realMin + x * (realMax - realMin) / (width - 1);
    double imaginaryPart = imaginaryMax - y * (imaginaryMax - imaginaryMin) / (height - 1);

    return new Complex(realPart, imaginaryPart);
  }

  public void calculateMandelbrotImagePoints() {
    Thread[] threads = new Thread[nThreads];
    int bandHeight = height / nThreads;

    for (int i = 0; i < nThreads; i++) {
      BufferedImage band = new BufferedImage(width, bandHeight, BufferedImage.TYPE_4BYTE_ABGR);
      threads[i] = new Thread(new MThread(band, i * bandHeight, bandHeight));
      threads[i].start();
    }
  }

  class MThread implements Runnable {
    final BufferedImage band;
    final Graphics2D g;
    final int top;
    final int height;

    private MThread(BufferedImage band, int top, int height) {
      this.band = band;
      g = band.createGraphics();
      this.top = top;
      this.height = height;
    }

    @Override
    public void run() {
      for (int x = 0; x < width; x++) {
        for (int y = top; y < top + height; y++) {
          int n = 0;
          Complex c = calculateComplexNumber(x, y);
          Complex z = c;

          while ((z.times(z).mod() < 4.0D) && (n < numberOfIterations)) {
            z = z.times(z).plus(c);
            n++;
          }

          if (n == numberOfIterations) {
            g.setColor(Color.BLACK);
          } else {
            g.setColor(Color.getHSBColor(n / 100.0F, 1, 1));
          }
          g.drawLine(x, y-top, x, y-top);
        }
      }
      // Do somehing to merge this band ino the main one.
      // Not familiar with java graphics so this may be wrong.
      imageGraphics.drawImage(band, null, 0, top);
    }
  }

}

1

要解决这个问题,请更改

if (n == numberOfIterations) { 
  imageGraphics.setColor(Color.BLACK); 
} else { 
  imageGraphics.setColor(Color.getHSBColor(n / 100.0F, 1, 1)); 
} 
imageGraphics.drawLine(x,y,x,y); 

to:

synchronized(MandelbrotSet.this) {
   if (n == numberOfIterations) { 
     imageGraphics.setColor(Color.BLACK); 
   } else { 
     imageGraphics.setColor(Color.getHSBColor(n / 100.0F, 1, 1)); 
   } 
  imageGraphics.drawLine(x,y,x,y); 
}

这将防止在更新图像期间出现线程冲突,但仍允许在多核系统上实现并发计算性能提升。


1

绘制不是线程安全的 - 一个线程可以重绘另一个线程的结果。

您可以使用volatile关键字创建结果的二维数组,表示生成的像素。线程可以在没有冲突的情况下保存到此数组中,并且当数组填满(线程结束,您可以使用.join()方法)时,可以一次性绘制所有内容。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接