2

Java の同期ブロックの概念を理解しようとしています。私が読んだドキュメントの時点で、ロック(インスタンス変数を使用した同期ブロック)を取得すると、そのクラスの同じオブジェクトの同期ロックを取得できないことがわかりました。しかし、次のスニペットを実際に使用してみると、私の理解が間違っていることがわかりました。

つまり、同時に 2 つの異なるメソッドでロック (同じインスタンス変数の同期ブロック) を取得できます。スレッドが開始されると、メソッドを実行し、無期限に待機し、同期ブロックから出ることはありません。同時に、同じスレッドを使用して stop メソッドを呼び出すと、同期ブロックに入り、notify ステートメントを実行します。Java doc を検索しましたが、何も見つかりませんでした。

これはコード スニペットです。

public class MyClass extends Thread
{
    private Object lock = new Object(); 
    public void run()
    {
      synchronized(lock)
      {
          lock.wait()
      }
      //other code
    }
    public void stop()
    {
      synchronized(lock)
      {
          lock.notify()
      }
      //other code
    } 
}

MyClass スレッドの管理方法のコード スニペットを次に示します。

public class MyClassAdmin 
{
    MyClass _myclass;
    public MyClassAdmin()
    {
        _myclass=new MyClass();
        _myclass.start();
    }
    public void stop()
    {
    _myclass.stop();
    }
    public static void main(String args[])
    {
    MyClassAdmin _myclassAdmin=new MyClassAdmin();
    _myclassAdmin.stop();
    }
}

私の理解によると、スレッドが開始されると、「ロック」オブジェクト(MyClassのrunメソッドの同期ブロック)でロックが取得されます。stop メソッドを呼び出すと、run メソッドが同期ブロックから出るまで無期限に待機する必要があります (この場合は発生しません)。しかし、私が実行したとき、メソッドを停止するための呼び出しが「ロック」オブジェクトのロックを取得し、オブジェクトに通知した結果、スレッドがシャットダウンしました。

4

2 に答える 2

2

どちらの方法も同じロックを使用します。メイン スレッドが stop メソッドを呼び出す前に MyClass スレッドがたまたま待機を開始した場合でも、待機中のスレッドがロックを解放するため、停止メソッドは続行できます。スレッドが待機メソッドに入ると、休止状態になる前にロックを解放し、待機メソッドを終了するまでロックを再取得しません。

これはObject#wait に関連する API ドキュメントです。2 番目の段落では、上記で説明した、wait がロックを解放する方法について説明しています。このメソッドをループで呼び出す必要があると書かれている部分に注意してください。そうしないと、他のスレッドが待機を開始する前にメイン スレッドに通知が到着したときに、待機中のスレッドがハングする原因となる順序依存性のバグが発生する可能性があります。

public final void wait() は InterruptedException をスローします

別のスレッドがこのオブジェクトの notify() メソッドまたは notifyAll() メソッドを呼び出すまで、現在のスレッドを待機させます。つまり、このメソッドは、wait(0) の呼び出しを実行するかのように動作します。

現在のスレッドは、このオブジェクトのモニターを所有している必要があります。スレッドは、このモニターの所有権を解放し、別のスレッドが、このオブジェクトのモニターで待機しているスレッドに、notify メソッドまたは notifyAll メソッドの呼び出しによってウェイクアップを通知するまで待機します。スレッドは、モニターの所有権を再度取得できるまで待機し、実行を再開します。

引数が 1 つのバージョンと同様に、割り込みと偽のウェイクアップが可能であり、このメソッドは常にループで使用する必要があります。

 synchronized (obj) {
     while (<condition does not hold>)
         obj.wait();
     ... // Perform action appropriate to condition
 }  

このメソッドは、このオブジェクトのモニターの所有者であるスレッドによってのみ呼び出される必要があります。スレッドがモニターの所有者になる方法については、notify メソッドを参照してください。

これはおもちゃの例ですが、Thread のサブクラス化と Thread メソッドのオーバーライドは混乱を招きます。Thread の代わりに Runnable を使用する理由の 1 つは、Thread メソッドを誤ってオーバーライドして問題を引き起こす可能性がないことです。

于 2016-03-02T14:22:40.813 に答える
-2

これはマルチスレッドであり、永遠に待機する場合とそうでない場合があります。あなたの場合、_myclassAdmin.stop(); は幸運でした。MyClass が実行を開始し、wait(); を実行した後に実行されました。

メソッド stop() の名前を stop1() に変更した後、プログラムを実行しました。

一貫した動作を得るには、次のようにメインの 2 つのメソッド呼び出しの間に 1 秒のスリープを入れます。

MyClassAdmin _myclassAdmin=new MyClassAdmin();
Thread.sleep(1)
_myclassAdmin.stop();

これで、実行は常に停止します。

また、スレッドが wait() を呼び出すと、それに関連付けられたモニターが解放されるため、他のスレッドはそのロックを取得し、notify() / notifyAll() を発行して、待機中のスレッドをウェイクアップできます。これは期待です

于 2016-03-02T12:21:13.200 に答える