2012-01-27 14 views
6

私は決して止めるべきではないテストアプリケーションを書いた。それはt.wait()tThreadオブジェクトです)を発行しますが、通知することはありません。なぜこのコードは終了するのですか? tでメインスレッドが同期しているにもかかわらず、生成されたスレッドが実行されるため、このオブジェクトはロックされません。Javaは待機スレッドに暗黙的に通知しますか?

public class ThreadWait { 
    public static void main(String sArgs[]) throws InterruptedException { 
     System.out.println("hello"); 
     Thread t = new MyThread(); 
     synchronized (t) { 
      t.start(); 
      Thread.sleep(5000); 
      t.wait(); 
      java.lang.System.out.println("main done"); 
     } 
    } 
} 

class MyThread extends Thread { 
    public void run() { 
     for (int i = 1; i <= 5; i++) { 
      java.lang.System.out.println("" + i); 
      try { 
       Thread.sleep(500); 
      } catch (Exception e) { 
       throw new RuntimeException(e); 
      } 
     } 
    } 
} 

この結果、メインスレッドは5秒間待機し、この間に作業者は出力を行います。 5秒後にプログラムは終了します。 t.wait()は待機しません。メインスレッドが5秒間スリープしない場合(この行にコメントする)、t.wait()は実際にワーカーが終了するまで待機します。もちろん、join()はここで使用する方法ですが、予期しないことにwait()join()と同じことを行います。どうして?

おそらく、JVMは、1つのスレッドしか実行されていないため、メインスレッドに通知する機会がなく、デッドロックを解決する可能性があります。これが正しければ、文書化された機能ですか?私はWindows XP上でテストしてい

+0

1秒または2秒間しか眠らないとどうなりますか?それから、メインスレッドがスレッドtが実行を終了するのを待つことになるでしょう。 – Renato

答えて

9

あなたはThreadに待っている - とほとんどのオブジェクトが暗黙的に通知さない間、スレッドが終了するときに、Threadオブジェクトが通知されます。それは内部で行われているように、ではないwait/notifyに、Threadオブジェクトで使用する必要があります(私はそれを探しています...)どこかで文書化されています。

これは、同期(および待機/通知)に「プライベート」オブジェクトを使用するのがよい理由の良い例です。あなたのコードが知っているものです。 。(一般的には、しかし、それはコメントで述べたようにあなたができる場合はjava.util.concurrentが提供する高いレベルの抽象化の一部を使用するクリーナーですが、それも良いことだ

private final Object lock = new Object(); 

:私は通常のようなものを使用します)

+0

スレッド内のメソッドの数は、そのオブジェクトで同期され、wait/notifyを使用するため、偽の起床が必要です。スレッドを拡張するのではなく、スレッドでラップされたRunnableを使用するのも良い方法です。これにより、この問題も回避されます。 –

+1

@PeterLawrey:OPがスレッドではなく実行可能ファイルに対してwait/notifyを使用している限り、私はまだどこでも*他の場所に公開しない「ダム」オブジェクトを好みます。 –

+0

理想的には、今後どのようにコードが変更されるかわからないので、両方とも必要です。最良の方法である複数の戦略を持つIMHOは、コードをより良く保護します。 –

8

waitためJavaDocのJava 6は答えを与える:スプリアスウェイクアップが可能です。これは、JVMがいつでも自由にwaitへの呼び出しを終了できることを意味します。

文書化しておけば、おそらくそうでない場合でも解決策が得られます。waitにループをかけて、ウェイクアップごとに条件がtrueになっているかどうかを確認してください。

+3

@Boris偽のウェイクアップの場合には、例外はありません。 InterruptedExceptionは、スレッドが中断したときにだけスローされます。 –

+2

私はこれが*実際には偽の起床であるとは思っていません - 特にスレッドで待っているのはそれだと思います。スレッドが終了すると通知されます。通常の意味では偽ではありません。 –

+2

偽のウェークアップがなくても、モニターパターン(またはその変種)を使用して、常にループして状態をチェックしたいと思っています。これにより、後で別の条件を追加した場合(JavaおよびC#モニターでは、ロックと条件変数の両方に1つのオブジェクトが使用されるため、条件ごとに1つの条件変数を使用することはできません)また、条件が満たされても、同じオブジェクトを待っている別のスレッドが先に実行された場合は、処理ができなくなり、条件はもはや真です。 –

関連する問題