2012-03-12 112 views
3

我想實現我的Java曼德爾布羅應用程序的多線程:多線程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; 

    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),將Mandelbrots繪製爲BufferedImage的最佳方式是什麼?

回答

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

} 
4

繪圖不是線程安全的,所以無法從多個線程繪製到同一個{screen,image,whatever}。這是可能的是這些線路之間中斷你的線程(即有可能發生上下文切換):

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

一個辦法是給每個線程提供自己的形象(比如,圖像的四分之一作爲瓷磚)來繪製,然後在最後繪製圖像。

1

繪圖不是線程安全的 - 一個線程可以重新繪製另一個線程的結果。

您可以使用volatile關鍵字創建結果的二維數組,以表示結果像素。線程可以在沒有衝突的情況下保存到這個數組中,並且當數組被填充時(線程結束,可以使用.join()方法),您可以一次繪製所有內容。

1

要解決該問題,改變

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

到:

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

這將防止圖像的更新過程中的線程衝突,但仍然允許你正在尋找的並行計算性能提升在多核系統上。