记一次神奇的 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已经包装类的时候,要小心!因为很可能只是值变了,但已经不是一个对象了!!!

posted @ 2021-11-26 17:12  刚刚好。  阅读(172)  评论(0编辑  收藏  举报