1

ジュリア集合を計算するプログラムを実装しています。使用可能なプロセッサの数に応じて、複数のスレッドが使用されます。各スレッドは行を計算しますが、その行が別のスレッドによって計算されていない場合のみです。この部分はかなりうまく機能します。

しかし、より大きな画像でテストする場合があります(たとえば、 の代わりに計算する行が多くgetHeight() = 1200、 に設定すると3000、スキップされる行がいくつかあります)。行が 2 回計算されたり、行がスキップされたりしないように、より安全にしたいと考えています。run()メソッドのコードは次のとおりです。

 public void run() {
     while (counter < getHeight()-1) {  
         synchronized(this) {
             if (counter >= getHeight() -1) { //so that the last line will not be calculated >2 times.
                 return;
             }
             counter++;
             image.setRGB(0, counter, getWidth(), 1, renderLine(counter), 0, 0);
         }
     }
  }

私はそれがそのように動作することを望みます:現在の行が計算されている場合、スレッドは次の行に進みます..混乱することなく、行がスキップされます..

私は実際にこれを試しています:

 public void run() {
     while (counter < getHeight()-1 && !working) {  
         synchronized(this) {
             working = true;
             if (counter >= getHeight() -1) { //so that the last line will not be calculated >2 times.
                 return;
             }
             counter++;
             image.setRGB(0, counter, getWidth(), 1, renderLine(counter), 0, 0);
             working = false;
         }
     }
  }

しかし、スレッドがすでに動作している間に別のスレッドへのアクセスが妨げられるかどうかはわかりません。また、「カウンター」の値が変更されるため、行をスキップできます。

スレッドが実際に回線で動作していることを通知するためにブール変数が必要ですか? 何かアドバイス?

4

2 に答える 2

5

ほとんどの場合、独自のスレッド管理を行いすぎています。を使用しExecutorServiceて、重複することなく複数のスレッド間で作業を分散します。

 ExecutorService service = Executors.newFixedThreadPool(
   Runtime.getRuntime().availableProcessors());
 for (int row = minRow; row <= maxRow; row++) {
   service.submit(new FillThisRowRunnable(row));
 }
于 2012-06-05T19:30:41.570 に答える
1

すべてのスレッドに共有オブジェクトが必要です。このオブジェクトは、どの行で作業するかを他のスレッドに伝えます。

あなたが今何を持っているかははっきりとはわかりませんが、それぞれsynchronizedが異なるインスタンスにあり、すべての相互排除が失われているようです. 同期は、共有オブジェクトで同期が発生する場合にのみ複数のスレッドに対して機能することに注意してください。それ以外の場合、各スレッドは、何も達成されないスレッド ローカル オブジェクトで同期します。

ここに例があります

public class SharedLineCounter{
   private final int maxNumberOfLines;
   private int currentLineNumber =0;
   public SharedLineCounter(int maxNumberOfLines){
      this.maxNumberOfLines = maxNumberOfLines;
   } 
   public synchronized int getNextLine(){
      if(++currentLineNumber > maxNumberOfLines)
         return -1; //end case
      return currentLineNumber ;
   }
}

public class WorkerThread extends Thread{
    private final SharedLineCounter counter;
    public WorkerThread(SharedLineCounter counter){
       this.counter = counter;
    }
    public void run(){
      int next = -1;
      while((next = counter.getNextLine()) >= 0){
        image.setRGB(0, next , getWidth(), 1, renderLine(next ), 0, 0);
      }
    }
  }
}

ここでは、各スレッドがこのスレッド セーフな行カウンターを共有するため、各スレッドは常に一意の連続した行番号を取得する必要があります。

あなたの質問に答えるために編集してください:

グローバルインスタンスを共有することで、スレッドを匿名にすることができます

public static void main(String args[]){
    final SharedCounter counter = new SharedCounter();

    Thread worker1 = new Thread(new Runnable(){
       public void run(){
            counter.getNextLine(); //etc
       }
    });
    Thread worker2 = new Thread(new Runnable(){
       public void run(){
            counter.getNextLine(); //etc
       }
    });

}

あなたのコメントに基づいて対処する1つの警告。を渡してnew Runnable匿名の実行可能ファイルを作成する必要があります。サブクラス化してrunメソッドをオーバーライドするのは悪い習慣です。Thread

于 2012-06-05T20:13:16.057 に答える