记一次神奇的 IllegalMonitorStateException 异常
public class StaticTest {
public static volatile Integer a=100 ;
public static void main(String[] args) throws InterruptedException {
new Thread(new Customer(),"哈哈").start();
Thread.sleep(1000);
}
}
static class Customer implements Runnable{
@Override
public void run() {
synchronized (a) {
System.out.println(Thread.currentThread().getName()+"获得锁");
a--;
a.notifyAll();
System.out.println("正在唤醒其他线程");
}
}
}
在一次多线程编程中,我遇到了IllegalMonitorStateException异常。
代码如上,当然真正的代码比这个复杂,我这里只是定位到了核心错误代码。
IllegalMonitorStateException异常发生在调用对象的wait(),notify(),notifyAll()方法时,没有获得对象的监视器锁
什么意思?
在上面的代码中,就是说我在a.notifyAll()时没有获得a的监视器锁。
不对啊,我不是用synchronized (a)把代码包裹起来了吗?为什么没获得a的监视器锁?
原来synchronized(a) 与 a.notifyAll() 时 两个 a 已经不是一个 a了!
Integer有个缓存池,在[-127,128]之间不会创建对象,而是会直接指向缓存池中的对象!
换句话说,我a=100时和a=99时,a指向的是不同的对象!
于是,代码修改如下
public class StaticTest {
public static volatile Integer a=100 ;
public static void main(String[] args) throws InterruptedException {
new Thread(new Customer(),"哈哈").start();
Thread.sleep(1000);
}
}
static class Customer implements Runnable{
@Override
public void run() {
synchronized (a) {
System.out.println(Thread.currentThread().getName()+"获得锁");
a.notifyAll();
System.out.println("正在唤醒其他线程");
}
}
}
果然,没有出错!
最后最后,给了我一个警醒,在使用String已经包装类的时候,要小心!因为很可能只是值变了,但已经不是一个对象了!!!
我有一壶酒
足以慰风尘
尽倾江海里
赠饮天下人