2016-06-17 13 views
1

私はjavaの並列スレッドで新しいです。私はシンプルな競馬シミュレーションをコーディングしようとしています。どのスレッドが同時スレッドで最初に終了しましたか?

最初に終了したスレッドを知りたい。互換性のない型:
以下このコードはエラーをスロースレッドがゲート

winner = (Gate)Thread.currentThread(); 
に変換できない

Gate.java

public class Gate implements Runnable{ 
    public String horseName; 
    public final int GATE_DISTANCE = 20; 
    public final int FINISH_LINE_DISTANCE = 100; 
    public CyclicBarrier barrier; 

    public Gate(CyclicBarrier barrier,String horseName){ 
     this.horseName = horseName; 
     this.barrier = barrier; 
    } 

    public void run(){ 
     //Walk all horses to respective racing gates before starting race 
     for(int distanceCovered = 0; distanceCovered < GATE_DISTANCE;){ 
      distanceCovered += gallop(); 
      int distanceLeft = GATE_DISTANCE - distanceCovered; 
      if(distanceLeft < 0){ 
       distanceLeft = 0;    
      } 
      System.out.println(horseName + "\t\tgate distance left " + distanceLeft); 
      if(distanceLeft == 0){ 
       break; 
      } 
     } 

     //Wait for all horses to be at racing gates 
     try{ 
      barrier.await(); 
     } 
     catch(InterruptedException ie){ 
      System.out.println("INTERRUPTED"); 
     } 
     catch(BrokenBarrierException bbe){ 
      System.out.println("BROKEN"); 
     } 

     //ACTUAL HORSE RACE 
     for(int distanceCovered = 0; distanceCovered < FINISH_LINE_DISTANCE;){ 
      distanceCovered += gallop(); 
      int distanceLeft = FINISH_LINE_DISTANCE - distanceCovered; 
      if(distanceLeft < 0){ 
       distanceLeft = 0;    
      } 
      System.out.println(horseName + "\t\tgate distance left " + distanceLeft); 
      if(distanceLeft == 0){ 
       break; 
      } 
     } 

     Main.done(); 
    } 

    public int gallop(){ 
     final int MIN_GALLOP = 1, 
         MAX_GALLOP = 10; 

     Random random = new Random(); 
     int gallopRange = MAX_GALLOP - MIN_GALLOP + 1; 
     int totalGallop = random.nextInt(gallopRange) + MIN_GALLOP; 
     return totalGallop; 
    } 
} 

GateMain.java

public class GateMain{ 
    private static Gate winner = null; 


    public static void main(String[] args) { 
     int horseCount = 5; 

     List<String> horseNames = new ArrayList<String>(); 
     List<Thread> RG = new ArrayList<Thread>(); 

     horseNames.add("Red Bullet"); 
     horseNames.add("Green Furious"); 
     horseNames.add("Pink Mirage"); 
     horseNames.add("Blue Dash"); 
     horseNames.add("Yellow Burst");  

     Scanner scan = new Scanner(System.in); 

     final CyclicBarrier cb = new CyclicBarrier(horseCount,new Runnable(){ 
      public void run(){ 
       System.out.print("\nALL HORSES ARE IN THEIR RESPECTIVE RACING GATES"); 
       System.out.println("\nRACE BEGIN!!!\n"); 
      } 
     }); 

     for(int horseCtr = 0; horseCtr < horseCount; horseCtr++){ 
      Gate rg = new Gate(cb,horseNames.get(horseCtr));    
      Thread thread = new Thread(rg); 
      thread.start(); 

      RG.add(thread); 
     } 

     for(Thread thread: RG){ 
      try{ 
       thread.join(); 
      } 
      catch(InterruptedException ie){ 
       System.out.println("Thread Interrupted"); 
      }   
     } 
     System.out.println(winner.horseName + "\t\t\twins!"); 
    } 

    synchronized static void done(){ 
     if(winner == null){ 
      winner = (Gate)Thread.currentThread(); 
     } 
    } 
} 

答えて

2

とラインMain.done()を交換してください。

public static AtomicInteger finishLine = new AtomicInteger(0); 

各馬(スレッド)は、独自のplace変数を持って

int place; 

と馬がレースを終了すると、それは自身の場所を設定する必要があります

place = finishLine.incrementAndGet(); 

最初の馬フィニッシュラインに達するには、place=1、第2の馬、place=2などが得られます。次に、main()ルーチンは、どの馬がplace=1を持っているか調べるために各馬を検査しなければならない。それが勝者になるでしょう。スレッドセーフなキューを使用し、代わりのAtomicIntegerの:ここで


はクロスカントリーフットレースのフィニッシュラインに触発異なる考え方、です。

public static ArrayBlockingQueue<Horse> chute = 
    new ArrayBlockingQueue<>(NUMBER_OF_HORSES); 

各馬がフィニッシュラインに到達すると、シュートに入る。

chute.add(this); 

この方法で、明示的に最後までレースを待つ必要はありません、と明示的に完走をソートする必要はありません。

Horse win = chute.take(); //waits for the first horse to finish 
Horse place = chute.take(); //waits for the second horse 
Horse show = chute.take(); //... 
+0

私はこの質問のメリットについて確信していませんが、私は答えが好きです。 –

1

しかし、ここで同期するだけではうまくいきませんJavaのルールスレッドに読み込みさせたい更新も同期させる必要があります。どの変数があるかによって、それは問題になる場合もあれば、そうでない場合もあります。

あなたのスレッドモデルをもう少し考えて、ここであなたがしたいことを説明する必要があるかもしれません。相互排除を認識していない場合は、スレッドコードを設計する準備ができていない可能性があります。

静的メンバーからインスタンスフィールドにアクセスしようとすると、コードをどのようにコンパイルするのだろうと思います。

Thread.currentThread()は、あなた(または他のライブラリコード)が作成した実際のThreadオブジェクトを返します。これはGateスレッドでもかまいませんが、実行中のThreadオブジェクトによって異なります。最も安全なのはinstanceofを使用して最初にチェックすることです。

0

docsによると、Thread.currentThread()は、オブジェクトではなく現在のスレッドへの参照を返します。したがって、オブジェクトへの参照、つまりthisキーワードを検索する必要があります。

winnerをプライベートメンバーにしたいと考えています。別のクラスのrun()から変更することはできません。したがって、run()の現在のオブジェクトを、GateMainのメソッドへの引数としてthisで渡すことができます。

あなたはとしてdone()方法を編集することができます。

synchronized static void done(Gate new_gate){ 
    if(winner == null){ 
     winner = new_gate; 
    } 
} 

私はグローバルAtomicIntegerを使用することになりMain.done(this)

+0

私はメインの 'の種類を交換することをお勧めしたいです.winner'から'AtomicReference 'に変更し、 'Main.winner.compareAndSet(null、new_gate)'を呼び出して 'syncronized'を削除することができます。 –

+0

Main.winnerのタイプをAtomicReference に変更して 'synchronized'を回避することはできますが、' Main.winner'をpublicにすることはできません。勝者を 'Main class'自体から変更する必要があります。 –

+0

私はフィールドを公開することについて何も言いませんでした。静的なので、 'Main.winner'は' Main.done'で受け入れられます。 –

関連する問題