多线程 Exception in thread “main” java.lang.IllegalMonitorStateException

调试多线程代码的时候,运行代码,报错如下:

Exception in thread "main" java.lang.IllegalMonitorStateException
	at java.lang.Object.wait(Native Method)
	at java.lang.Object.wait(Object.java:502)
	at com.itzhimei.base.design.test1.SingletonLazy.main(SingletonLazy.java:47)

我是要模拟多线程并发创建单例对象,看看是否最终获取的是同一对象,结果报错了。代码如下:

/**
 * 懒汉式单例
 */
public class SingletonLazy {

    private static SingletonLazy singletonLazy = null;

    private SingletonLazy() {

    }

    public static SingletonLazy getInstance() {
        if(singletonLazy == null) {
            synchronized (SingletonLazy.class) {
                if(singletonLazy == null) {
                    singletonLazy = new SingletonLazy();
                }
            }
        }
        return singletonLazy;
    }

    public static void main(String[] args) throws InterruptedException {
        //多线程模拟创建单例
        CountDownLatch cd1 = new CountDownLatch(1);
        CountDownLatch cd5 = new CountDownLatch(5);

        for(int i=0; i<5; i++) {
            new Thread(()->{
                try {
                    System.out.println("SingletonLazy.getInstance()");
                    cd1.await();
                    System.out.println(SingletonLazy.getInstance());
                    cd5.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
        System.out.println("main");
        Thread.sleep(1000);
        cd1.countDown();
        cd5.wait();
    }
}

仔细查看代码,发现问题很简单,是因为CountDownLatch的API用错了,CountDownLatch阻塞线程的API是await(),实际敲代码敲成了wait(),所以报了上面的错。

但是使用了wait()为什么会报这个错,因为JDK规定,如果使用wait()方法,有两个原则必须满足其中一个,一是要么放到Synchronized中的,没有在Synchronized包裹的代码中使用wait()方法,则会报这个错;二是要么保证是同一把锁,如果锁是this,但是你用a.wait(),那么也会报错。

我们上面的代码显然两个问题都存在,所以报错是必然的。