2012-07-22 18 views
5

SlaveThreadオブジェクトのリストを保持するマスターがあるとします。各ステップでは、マスターがSlaveThreadsを同時に実行するようにしますが、タイムステップの最後に、SlaveThreadsが前進する前に現在のタイムステップを完了するまで待ちます。また、私は各時間ステップでSlaveThreadsを再インスタンス化したくありません。私は2つの可能な解決法があり、どちらかを動作させる方法がわかりません:1)SlaveThreadのrun()メソッドはwhile(真)ループにあります。 SlaveThreadでの単一ループの実行後に、私が持っているでしょうSlaveThreadは(私が方法がわからない)マスターに通知し、マスターは前Java - タイムステップごとに複数のスレッドを同期する

try{ 
    for (int i = 0; i < numSlaveThreads; i++) { 
     while (!slaveThreads[i].getCompletedThisIter()) { 
     wait() 
     } 
     } 
    System.out.println("Joined"); 

のようなもの}

を行います次の時間ステップに進む。どうすればいい? SlaveThreadをマスターに通知するにはどうすればよいですか?

2)Slaveのrun()がwhile(true)ループにない場合は、すべての繰り返しでstart()を呼び出す必要があります。しかし、この時点でスレーブのスレッド状態は終了します。どのように私はそれを再インスタンス化せずに、再びstart()を呼び出すことができますか?

+0

サウンズ/java/util/concurrent/CyclicBarrier.html(バリアント1を使用) – millimoose

答えて

5

これはまさに障壁のためのもので、CyclicBarrierまたはCountDownLatchでこれを実現できます。これらは、同期に使用される希望の状態に達するまでスレッドの進捗を遅らせるあなたのケースでは、スレッドが計算を完了しました。

ここでは、あなたが実現する方法の詳細に依存します:

ラッチはイベントを待っているためです。障壁は他のスレッドを待つためのものです スレッド。以下の方法で行われますCyclicBarrierについては

// whereby count is the number of your slave threads 
this.barrier = new CyclicBarrier(count); 

次に、あなたの奴隷のRunnable定義にあなたは計算の最後に挿入されます:barrier.await()

public class Slaves implements Runnable { 

    // ... 

    @Override 
    public void run() { 

     while(condition) { 

     // computation 
     // ... 

     try { 
      // do not proceed, until all [count] threads 
      // have reached this position 
      barrier.await(); 
     } catch (InterruptedException ex) { 
      return; 
     } catch (BrokenBarrierException ex) { 
      return; 
     } 
     } 
    } 
} 

すべてのスレッドが計算を終了するまで、スレーブスレッドは進まないでしょう。この方法では、別のマスタースレッド間でシグナリングを実現する必要はありません。

、しかし、あなたはすべてのスレッドがその位置(マスターシグナリング)に達した後、あなたはすべてのスレッドがバリアに到着した後に実行されますCyclicBarrierコンストラクタに追加Runnableを渡すことができます実行するいくつかのコードを持っている場合。

this.barrier = new CyclicBarrier(count, 
    new Runnable() { 
     @Override 
     public void run() { 
     // signal your master thread, update values, etc. 
     } 
    } 
); 
+0

他のスレッドが現在の繰り返しで完了したことをマスターに伝えるのを待っています(すべてのスレッドが同時に次のスレッドに進むことができるようにします)。 1) – Trup

+0

1回の反復の最後に循環バリアがカウントを再開させる方法を教えてください。あなたはawait()を呼び出すことによって各スレッドが0になるまでカウンタを1減らしますが、その時点で、次のサイクルが実行されるようにnumThreadsに戻ってカウンタを再起動したいとしました。 – Trup

+0

@Trupあなたはそれを心配する必要はありません。これは自動的に起こります。そのため、サイクリング*バリアと呼ばれ、頻繁に再利用することができます。 –

3

あなたは(すなわち、各サイクルで新しいものを作成することなく、あなたのスレッドを再利用)あなたのスレッドを管理するためにExecutorServiceの組み合わせを使用することができ、すべてのスレーブを同期しますCyclicBarrier

マスターがループ内のスレーブを起動し、すべてがスレーブを再起動する前に完了していることを確認する簡単な例を以下に示します。少し怠けているスレーブは、単にいくつかの(実際にはランダムではない)時間睡眠:http://docs.oracle.com/javase/7/docs/api:あなたは、環状の障壁をしたいよう

public class Test { 

    private static final ExecutorService executor = Executors.newFixedThreadPool(5); 
    private static final CyclicBarrier barrier = new CyclicBarrier(5); //4 slaves + 1 master 

    public static void main(String[] args) throws InterruptedException { 
     Runnable master = new Runnable() { 
      @Override 
      public void run() { 
       try { 
        while (true) { 
         System.out.println("Starting slaves"); 
         for (int i = 100; i < 500; i += 100) { 
          executor.submit(getRunnable(i)); 
         } 
         barrier.await(); 
         System.out.println("All slaves done"); 
        } 
       } catch (InterruptedException | BrokenBarrierException ex) { 
        System.out.println("Bye Bye"); 
       } 
      } 
     }; 

     executor.submit(master); 
     Thread.sleep(2000); 
     executor.shutdownNow(); 

    } 

    public static Runnable getRunnable(final int sleepTime) { 
     return new Runnable() { 
      @Override 
      public void run() { 
       try { 
        System.out.println("Entering thread " + Thread.currentThread() + " for " + sleepTime + " ms."); 
        Thread.sleep(sleepTime); 
        System.out.println("Exiting thread " + Thread.currentThread()); 
        barrier.await(); 
       } catch (BrokenBarrierException | InterruptedException ex) { 
       } 
      } 
     }; 

    } 
} 
+0

スレーブのコードはどれですか?また、私は周期的な障壁と実行サービスなしでそれを行うことはできますか?これがどのように見えるか私に見せてもらえますか?基本的に、私は、スレーブがサイクリックバリアをどのように伝えるのかを明示的に見たいと思っています。マスターがサイクリックバリアを使ってすべてのスレーブが終了するのを待つ方法を見ていきたいと思います。ありがとう! – Trup

+0

スレーブのランナブルは 'getRunnable(i)'によって生成されます。あなたはexecutorerviceなしでcyclicbarrierを使うことができます。適切な番号で障壁を設定するだけです。 'barrier.await()'が呼び出されるたびに、呼び出し側スレッドが待機し、その番号が減少します。番号が0になると、待機中のすべてのスレッドが再び動作を開始します。 – assylias

+0

私はそれがどのように動作し、あなたのニーズに適応するかを確認するために投稿したプログラムを実行することをお勧めします。 – assylias

関連する問題