java.lang.IllegalMonitorStateException:notify()の前にスレッドによってロックされていないオブジェクト



Java Lang Illegalmonitorstateexception



エラーログ:

2019-04-11 17:03:43.799 13792-13808/? E/AndroidRuntime: FATAL EXCEPTION: Thread-2 Process: com.pipiyang.cn03, PID: 13792 java.lang.IllegalMonitorStateException: object not locked by thread before notify() at java.lang.Object.notifyAll(Native Method) at com.example.getphoneapplication.WaitTest$1.run(WaitTest.java:32)

書く場所に電話してください:

WaitTest waitTest = new WaitTest() Log.d('xinyu2',waitTest.getString())

問題のあるクラスの記述方法:

package com.example.getphoneapplication /** * ======================================================================================= * Author: caoxinyu * Creation date: 2019/4/11. * The role of the class: * revise history: * ======================================================================================= */ public class WaitTest { private boolean mloaded = false private final Object mlock = new Object() public WaitTest() { loadFromDisk() } private void loadFromDisk() { new Thread(){ @Override public void run() { synchronized (WaitTest.this){ super.run() try { sleep(3000) } catch (InterruptedException e) { e.printStackTrace() } mloaded = true notifyAll() } } }.start() } public String getString(){ synchronized (WaitTest.this){ while (!mloaded) { try { wait() } catch (InterruptedException e) { e.printStackTrace() } return 'success' } return '' } } }

クラス1を書くのに問題ありません

package com.example.getphoneapplication /** * ======================================================================================= * Author: caoxinyu * Creation date: 2019/4/11. * The role of the class: * revise history: * ======================================================================================= */ public class WaitTest { private boolean mloaded = false private final Object mlock = new Object() public WaitTest() { loadFromDisk() } private void loadFromDisk() { new Thread(){ @Override public void run() { synchronized (WaitTest.this){ super.run() try { sleep(3000) } catch (InterruptedException e) { e.printStackTrace() } mloaded = true WaitTest.this.notifyAll() } } }.start() } public String getString(){ synchronized (WaitTest.this){ while (!mloaded) { try { WaitTest.this.wait() } catch (InterruptedException e) { e.printStackTrace() } return 'success' } return '' } } }

クラス2を書くのに問題ありません

package com.example.getphoneapplication /** * ======================================================================================= * Author: caoxinyu * Creation date: 2019/4/11. * The role of the class: * revise history: * ======================================================================================= */ public class WaitTest { private boolean mloaded = false private final Object mlock = new Object() public WaitTest() { loadFromDisk() } private void loadFromDisk() { new Thread(){ @Override public void run() { synchronized (WaitTest.this){ super.run() try { sleep(3000) } catch (InterruptedException e) { e.printStackTrace() } doLoad() } } }.start() } private void doLoad() { mloaded = true notifyAll() } public String getString(){ synchronized (WaitTest.this){ while (!mloaded) { try { wait() } catch (InterruptedException e) { e.printStackTrace() } return 'success' } return '' } } }

理由:

匿名内部クラスでnotifyを呼び出すと、匿名内部クラスの通知が呼び出され、匿名内部クラスは同期されません。
最初のメソッドが変更された後:
doLoadをクラス全体に抽出します。今回は、匿名内部クラスのnotifyAllとは呼ばれません。これはWaitTestのnotifyAll()です

private void doLoad() { mloaded = true notifyAll() }

2番目の変更方法は、WaitTest.this.notifyAll()を呼び出すことです。



総括する:

通知を確実に呼び出すオブジェクトは、同期されたオブジェクトです。

私は、AndroidソースコードSharedPreferencesImplを表示しても彼の記述に問題はなく、彼がメソッドをメインクラスに抽出し、メインクラスのnotifyを呼び出したため、私の記述方法に問題があると述べました。簡単な抽出方法があります。抽出方法にも問題があります。