2011-08-01 8 views
4

私のインスタンスに、この結果を生成し、次の2つのクラスのコードを持っている:のJavaスレッドの同期問題

Wainting for calculation to complete... 
Calculator thread says HELLO! 
T1 says that total is 10 
Wainting for calculation to complete... 
Wainting for calculation to complete... 

今のスレッドが待っているが、誰もがそれらを通知するつもりはありません。 "Calculator thread"が起動する前に、スレッドを強制的にT1からT3に強制的に実行させることはできますか?

public class Calculator implements Runnable{ 

    private int total; 

    public int getTotal() { 
    return total; 
    } 

    @Override 
    public void run() { 
    synchronized (this) { 

     for (int i = 0; i < 5; i++) { 
      total += i; 
     } 
     System.out.println(Thread.currentThread().getName() + " says HELLO!"); 
     notifyAll(); 
    } 
    } 
} 


import static java.lang.System.out; 

public class Reader implements Runnable{ 

    private Calculator c; 


    public Reader(Calculator calc) { 
    c = calc; 
    } 

    public Calculator getCalculator() { 
    return c; 
    } 

    public static void main(String[] args) { 

    Calculator calc = new Calculator(); 
    Reader read = new Reader(calc); 

    Thread thread1 = new Thread(read); 
    Thread thread2 = new Thread(read); 
    Thread thread3 = new Thread(read); 

    thread1.setName("T1"); 
    thread2.setName("T2"); 
    thread3.setName("T3"); 

    thread1.start(); 
    thread2.start(); 
    thread3.start(); 

    Thread calcThread = new Thread(read.getCalculator()); 
    calcThread.setName("Calculator thread"); 
    calcThread.start(); 
    } 
} 


    @Override 
    public void run() { 
     synchronized (c) { 
      try { 
       out.println("Wainting for calculation to complete..."); 
       c.wait(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
      out.println(Thread.currentThread().getName() + " says that " + "total is " + c.getTotal()); 
     } 

    } 

} 
+0

thread3.start()の後にThread.sleep()を追加できますが、これは適切な解決策ではないと考えています。 – nyxz

+0

wait/notifyを使用するのではなく、java.util.concurrentのデバッグされたユーティリティを使用して、アプリケーションを完全に再設計してください。あなたの本当のアプリケーションが何であるかははっきりしていないので、あなたが使っているべきことを本当に教えてくれません。 – toto2

+0

@toto:wait/notifyを使うべきではありません。それらはシンプルで魅力的なプリミティブです。 java.util.concurrentクラスは、同じクラスのラッパーです。私は読み書きロック、障壁、ラッチなどのより高いレベルの構造がこれらのクラスによって提供されることに同意します。しかし、単純なハンマーで十分である場合はアンビルを使用するべきではありません。 –

答えて

0

Thread.join()は、この特定の状況ではオプションのように見えるかもしれませんかどうかはわかりません。 main()関数を制御し、各スレッドがいつ起動しているかを正確に知っているからです。

この状況を処理するより一般的な方法は、条件変数を使用し、ループ内でc.wait()を呼び出して条件変数をチェックすることです。

基本的にCalculatorクラスでisFinishedフィールドを追加します。

 
public class Calculator implements Runnable { 
... 
    public volatile boolean isFinished = false 
.. 
.. 

次にあなたがc.wait()を置き換える:合計を計算した後

あなたのCalculatorクラスの `run()メソッドで最後に
 
... 
while (!c.isFinished) { 
    c.wait(); 
} 
... 

、 isFinishedフィールドを設定する

 
.... 
for(int i = 0; .... 
    total = += i; 
} 
c.isFinished = true 
.... 
+0

私もそれを試してみます、ありがとう – nyxz

+0

これは役に立ちません。 – nyxz

+0

申し訳ありませんが、私の悪い!それは助け:)これは素晴らしい単純な解決策です。 – nyxz

3

これはコードの記述方法です。 wait/notifyでホイールを再作成しようとするのではなく、必要なことを実行するために並行性ライブラリを使用します。

thread3.start(); 

import java.util.concurrent.*; 

public class Main { 
    static final long start = System.nanoTime(); 

    static void log(String text) { 
     double seconds = (System.nanoTime() - start)/1e9; 
     System.out.printf("%s %.6f - %s%n", Thread.currentThread().getName(), seconds, text); 
    } 

    static class Calculator implements Callable<Integer> { 
     @Override 
     public Integer call() throws Exception { 
      int total = 0; 
      log("calculating total"); 
      for (int i = 0; i < 50000; i++) 
       total += i; 
      log("total is " + total); 
      return total; 
     } 
    } 

    static class Reader implements Callable<Void> { 
     private final Future<Integer> totalFuture; 

     public Reader(Future<Integer> totalFuture) { 
      this.totalFuture = totalFuture; 
     } 

     @Override 
     public Void call() throws ExecutionException, InterruptedException { 
      log("Waiting for total."); 
      int total = totalFuture.get(); 
      log("... got total= " + total); 
      return null; 
     } 
    } 

    public static void main(String... args) { 
     ExecutorService es = Executors.newCachedThreadPool(); 
     Future<Integer> totalFuture = es.submit(new Calculator()); 
     es.submit(new Reader(totalFuture)); 
     es.submit(new Reader(totalFuture)); 
     es.submit(new Reader(totalFuture)); 
     es.shutdown(); 
    } 
} 

プリント

pool-1-thread-1 0.008154 - calculating total 
pool-1-thread-4 0.011356 - Waiting for total. 
pool-1-thread-3 0.011292 - Waiting for total. 
pool-1-thread-2 0.011128 - Waiting for total. 
pool-1-thread-1 0.025097 - total is 1249975000 
pool-1-thread-4 0.025351 - ... got total= 1249975000 
pool-1-thread-3 0.025372 - ... got total= 1249975000 
pool-1-thread-2 0.025380 - ... got total= 1249975000 

スレッドが終了するのを待つために、以下を追加します。

thread1.join(); 
thread2.join(); 
thread3.join(); 
+0

スーパー!ありがとう、ピーター! – nyxz

+0

コードを編集しました。誤ってロールをいくつか削除しました。 このコードを追加すると、スレッドは実際に完了するのを待っており、プログラムはcalcThread.start()に到達しません。魔女はnotifyAll()メソッドを呼び出します...プログラムは決して終了しません。 他の提案はありますか? – nyxz

+0

問題は、合計文と1つのprint文を計算するループが1つだけあるまで、必要のないすべてのコードを削除することです。他のすべては本当に何もしません。 –

0

UはThread.join()メソッドを使用することができます..私は良いプログラミングプラクティスが、それがうまくいくのabouts ..

+0

コメントを見る私はPeter Lawreyにjoin()を使って残しました – nyxz