为何使用flag作为同步对象调用notify时抛出IllegalMonitorStateException?
为什么用Boolean对象做锁并调用notify会抛出IllegalMonitorStateException?
我在实现交替输出“1a2b3c……”的功能时,明明把flag.notify()放在了synchronized代码块里,却还是抛出java.lang.IllegalMonitorStateException: current thread is not owner异常。但换成其他对象做同步锁并调用其notify方法时,程序就能正常运行,想知道这是为什么?
问题代码
class Main{ static volatile Boolean flag = true; static int cnt = 26; public static void main(String[] args) { new Thread(() -> { for (int i = 1; i <= cnt; i++) { synchronized (flag) { try { while(!flag) flag.wait(); System.out.print(i); flag = false; flag.notify(); } catch (InterruptedException e) { throw new RuntimeException(e); } } } }).start(); new Thread(() -> { for (int i = 0; i < cnt; i++) { synchronized (flag) { try { while(flag) flag.wait(); System.out.print((char) (i + 'a')); flag = true; flag.notify(); } catch (InterruptedException e) { throw new RuntimeException(e); } } } }).start(); } }
正常运行示例代码
class Main{ static volatile Boolean flag = true; static Object obj = new Object(); static int cnt = 26; public static void main(String[] args) { new Thread(() -> { for (int i = 1; i <= cnt; i++) { synchronized (obj) { try { while(!flag) obj.wait(); System.out.print(i); flag = false; obj.notify(); } catch (InterruptedException e) { throw new RuntimeException(e); } } } }).start(); new Thread(() -> { for (int i = 0; i < cnt; i++) { synchronized (obj) { try { while(flag) obj.wait(); System.out.print((char) (i + 'a')); flag = true; obj.notify(); } catch (InterruptedException e) { throw new RuntimeException(e); } } } }).start(); } }
原因解释
核心问题出在锁对象的引用被修改:
Boolean是不可变类,flag = false或flag = true并不是修改原有Boolean对象的值,而是让flag变量指向了全新的对象(Java中Boolean.TRUE和Boolean.FALSE是预定义的常量实例)。- 进入
synchronized (flag)代码块时,线程持有的是当前flag指向的那个对象的锁;但执行flag = false后,flag已经指向另一个对象,此时调用flag.notify(),实际是对新对象调用notify,但当前线程并没有持有这个新对象的锁,因此抛出IllegalMonitorStateException。 - 正常运行的代码中,锁对象是
obj,其引用全程没有被修改,每次synchronized (obj)持有的都是同一个对象的锁,调用obj.notify()时线程确实持有该锁,所以不会报错。
额外提醒:无论用什么对象做锁,都绝对不能修改锁对象的引用,必须保证同步过程中锁是同一个实例。
内容的提问来源于stack exchange,提问作者SomeOne
相关产品推荐
相关产品推荐

