2

私はJavaマルチスレッドに取り組んでいます。私は C/C++ pthreads に精通していますが、Javanotify()wait()関数に問題があります。

IllegalMoinitorStateException「所有」していない(同期していない)スレッドが通知/待機を呼び出した場合にのみスローされることを理解しています。

アプリケーションを作成しているときに、この問題に遭遇しました。次のテスト コードで問題を切り分けました。

public class HelloWorld
{
    public static Integer notifier = 0;
    public static void main(String[] args){
        notifier = 100;
        Thread thread = new Thread(new Runnable(){
            public void run(){
                    synchronized (notifier){
                            System.out.println("Notifier is: " + notifier + " waiting");
                            try{
                                notifier.wait();
                                System.out.println("Awake, notifier is " + notifier);
                            }
                            catch (InterruptedException e){e.printStackTrace();}
                    }
            }});
        thread.start();
        try{
                Thread.sleep(1000);
            }
        catch (InterruptedException e){
                e.printStackTrace();
            }
        synchronized (notifier){
            notifier = 50;
            System.out.println("Notifier is: " + notifier + " notifying");
            notifier.notify();
        }
        }
    }

これは以下を出力します:

    Exception in thread "main" java.lang.IllegalMonitorStateException
        at java.lang.Object.notify(Native Method)
        at HelloWorld.main(HelloWorld.java:27)

通知オブジェクトのロックを既に取得していると思います。私は何を間違っていますか?

ありがとう!

編集:

この可能な重複 (整数値での同期) から、同じインスタンスで同期していることを確認するのが難しいため、整数で同期することはお勧めできません。同期している整数はグローバル可視静的整数であるため、異なるインスタンスを取得するのはなぜですか?

4

3 に答える 3

5

別のオブジェクトnotifier = 50;を呼び出しているためです。notifier.notify();

于 2013-03-23T19:28:55.650 に答える
0

notifier最初に、非メイン スレッドでsynchronized を呼び出したとき、コンテンツがあった0ため、スレッドがそのオブジェクトを所有しているヒープ上のオブジェクトを参照していました。非メイン スレッドがwait使用された後notifier.wait、コントロールがメイン スレッドに渡されます。値 0 を含む Integer のオブジェクトのロックを取得した後、値notifierを含むヒープ メモリ上の他のオブジェクトを参照するようにしました。これは、 の新しいオブジェクトが作成され、その参照が に渡されることを意味する50ためです。ここで、スレッドが確認すると、メイン スレッドは以前に取得した元のオブジェクトを所有していないように見えます。投げも同様です。notifier = 50;notifier = new Integer(50)Integernotifiernotifier.notifyIllegalMonitorStateException

于 2013-03-23T19:43:41.520 に答える
0

さらに情報を追加するために、非最終オブジェクトで同期しないでください。

定数オブジェクトで同期する必要があります。割り当てているオブジェクトを同期した場合 (つまり、オブジェクトを変更した場合)、オブジェクトは一定ではなく、オブジェクトを割り当てて通知しようとすると、IllegalMonitorStateException. また、異なるオブジェクトで同期しているため、複数のスレッドが同時に保護されたブロックに入り、競合状態が発生することも意味します。

同期している整数はグローバル可視静的整数であるため、異なるインスタンスを取得するのはなぜですか?

に値を代入すると、たとえそれが であっても、別のIntegerオブジェクト参照に変更されます。変更できないため、同じオブジェクトを変更していません。そのため、 とは別のオブジェクトに割り当てます。staticIntegernotifier = 50;notifier = 0;

たとえば、定数オブジェクトを使用する場合は、次を使用できますAtomicBoolean

  public static final AtomicInteger notifier = new AtomicInteger(0);
  ...
  synchronize (notifier) {
      notifier.set(50);
      ...
  }

ここでは、常に同じオブジェクトであるため、AtomicIntegerマークを付けることができます。final

詳細については、次を参照してください: Boolean で同期することが適切でないのはなぜですか?

于 2013-03-24T11:16:21.530 に答える