web-dev-qa-db-ja.com

java.lang.IllegalMonitorStateException:(m = null)のモニターの取得に失敗しました

なぜこれが起こるのでしょうか?問題は、モニターオブジェクトが確かにnullではないことですが、それでもこの例外は頻繁に発生します。

_Java.lang.IllegalMonitorStateException: (m=null) Failed to get monitor for (tIdx=60)
        at Java.lang.Object.wait(Object.Java:474)
        at ...
_

これを引き起こすコードは、単純なプールソリューションです。

_    public Object takeObject() {
        Object obj = internalTakeObject();
        while (obj == null) {
            try {
                available.wait();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            obj = internalTakeObject();
        }
        return obj;
    }

    private Object internalTakeObject() {
        Object obj = null;
        synchronized (available) {
            if (available.size() > 0) {
                obj = available.keySet().iterator().next();
                available.remove(obj);
                synchronized (taken) {
                    taken.put(obj, Boolean.valueOf(true));
                }
            }
        }
        return obj;
    }

    public void returnObject(Object obj) {
        synchronized (taken) {
            taken.remove(obj);
        }
        synchronized (available) {
            if (available.size() < size) {
                available.put(obj, Boolean.valueOf(true));
                available.notify();
            }
        }
    }
_

何か不足していますか?

[〜#〜] edit [〜#〜]:例外はavailable.wait();行で発生します。

35

Object.waitのjavadocを参照してください。

特に、「現在のスレッドがこのオブジェクトのモニターを所有している必要があります。」および「[スロー] IllegalMonitorStateException-現在のスレッドがオブジェクトのモニターの所有者でない場合」つまり、wait onを呼び出すオブジェクトで同期する必要があります。

あなたのコードは次のようになります:

synchronized (available) {
    available.wait();
}
69
tgdavies

available.wait();はsynchronized(available)セクションにある必要があります

7
Maurice Perry

「IllegalMonitorStateException」を取得しています

available.wait()

wait()メソッドを呼び出す現在のスレッドは、「使用可能な」オブジェクト参照によって参照されるオブジェクトのモニターの所有者ではないためです。

スレッドがオブジェクトのモニターの所有者になるには、3つの方法があります。

  1. そのオブジェクトの同期インスタンスメソッドを実行する。
  2. オブジェクトで同期する同期ブロックの本体を実行する。
  3. Classクラスのオブジェクトの場合、そのクラスの同期静的メソッドを実行します。

各シナリオの簡単なサンプルコード。 3つのコードスニペットはすべて、タイプごとに個別のクラスであり、コードをコピーして実行するだけです。各ケースで何が起こっているのかを説明するために、コードにコメントを大幅に追加しました。コメントが多すぎる場合。コードをより簡潔にするためにそれらを削除してください。

また、最初にmain()メソッドのコードを読んで、threadOneとthreadTwoについて最初に考えてください。

  1. そのオブジェクトの同期インスタンスメソッドを実行する。

    import static Java.lang.System.out;
    
    public class SynchronizedInstanceMethodClass {
    
        synchronized void synchronizedInstanceMethod() { // threadOne acquire the monitor for "this" and continue.
    
                try {
    
                    out.println("EVENT #1 threadOne is about to strat waiting on the "
                            +"monitor it already has - [\"this\"]....");
    
                    this.wait(); // The threadOne already have the monitor for "this", 
                                //  just release the monitor and go and wait threadOne.
    
                    out.println("EVENT #3 Notify received and continue execution...");
    
                } catch (InterruptedException interruptedException) {
                    interruptedException.printStackTrace();
                }
        }
    
    
        synchronized void notifierForAllThreads() { // threadTwo acquire the monitor for "this", 
                                                   // which was released by threadOne when it went to waiting and contine.
    
                out.println("EVENT #2 threadTwo is about to notify all threads(including threadOne) "
                        +"   waiting on the monitor of -[\"this\"]....");
    
                this.notifyAll(); // threadTwo who owns the monitor on "this" notifies all 
                                 // threads waiting on "this" and releases the monitor
        }
    
        public static void main(String [] args) {
    
            SynchronizedInstanceMethodClass mc  = new SynchronizedInstanceMethodClass();
            Thread threadOne = new Thread(() -> {mc.synchronizedInstanceMethod();});
            Thread threadTwo = new Thread(() -> {mc.notifierForAllThreads();});
    
            threadOne.start(); // Start the waiting of Thread one
            threadTwo.start(); // Notify the waiting threadOne
        }
    
    }
    
  2. オブジェクトで同期する同期ブロックの本体を実行する。

    import static Java.lang.System.out;
    
    public class SynchronizedBlockClass {
    
        void synchronizedBlockInstanceMethod() {
    
            synchronized (this) { // threadOne acquire the monitor for "this" and continue.
    
                try {
    
                    out.println("EVENT #1 threadOne is about to strat waiting on the "
                                +"monitor it already has - [\"this\"]....");
    
                    this.wait(); // The threadOne already have the monitor for "this", 
                                //  just release the monitor and go and wait threadOne.
    
                    out.println("EVENT #3 Notify received and continue execution...");
                } catch (InterruptedException interruptedException) {
                    interruptedException.printStackTrace();
                }
            }
        }
    
    
        void synchronizedBlockNotifierForAllThreads() {
    
            synchronized (this) { // threadTwo acquire the monitor for "this", 
                                 // which was released by threadOne when it went to waiting and continue.
    
                    out.println("EVENT #2 threadTwo is about to notify all threads(including threadOne) "
                            +"   waiting on the monitor of -[\"this\"]....");
    
                    this.notifyAll(); // threadTwo who owns the monitor on "this" notifies all 
                                     // threads waiting on "this" and releases the monitor
                }
        }
    
        public static void main(String [] args) {
            SynchronizedBlockClass mc  = new SynchronizedBlockClass();
            Thread threadOne = new Thread(() -> {mc.synchronizedBlockInstanceMethod();});
            Thread threadTwo = new Thread(() -> {mc.synchronizedBlockNotifierForAllThreads();});
    
            threadOne.start(); // Start the waiting of Thread one
            threadTwo.start(); // Notify the waiting threadOne
        }
    
    }
    
  3. Classクラスのオブジェクトの場合、そのクラスの同期静的メソッドを実行します。

    import static Java.lang.System.out;
    
    public class StaticClassReferenceClass {
    
        void synchronizedBlockInstanceMethod() {
    
            synchronized (StaticClassReferenceClass.class) { // threadOne acquire the monitor for class literal and continue.
    
                try {
    
                    out.println("EVENT #1 threadOne is about to strat waiting on the "
                                +"monitor it already has - [StaticClassReferenceClass.class]....");
    
                    StaticClassReferenceClass.class.wait(); // The threadOne already have the monitor for the class literal, 
                                //  So it just release the monitor and go and wait.
    
                    out.println("EVENT #3 Notify received and continue execution...");
                } catch (InterruptedException interruptedException) {
                    interruptedException.printStackTrace();
                }
            }
        }
    
    
        void synchronizedBlockNotifierForAllThreads() {
    
            synchronized (StaticClassReferenceClass.class) { // threadTwo acquire the monitor for the class literal, 
                                 // which was released by threadOne when it went to waiting.
    
                    out.println("EVENT #2 threadTwo is about to notify all threads(including threadOne) "
                            +"   waiting on the monitor of -[StaticClassReferenceClass.class]....");
    
                    StaticClassReferenceClass.class.notifyAll(); // threadTwo who owns the monitor on the class literal notifies all 
                                     // threads waiting on it and releases the monitor
                }
        }
    
        public static void main(String [] args) {
            StaticClassReferenceClass mc  = new StaticClassReferenceClass();
            Thread threadOne = new Thread(() -> {mc.synchronizedBlockInstanceMethod();});
            Thread threadTwo = new Thread(() -> {mc.synchronizedBlockNotifierForAllThreads();});
    
            threadOne.start(); // Start the waiting of Thread one
            threadTwo.start(); // Notify the waiting threadOne
        }
    
    }
    

takeObject()メソッドは同期する必要があります。または、このメソッド内にsynchronizedブロックを記述する必要があります。このためにコンパイル時の例外が発生することを願っています。

0
prasad