调试多线程代码的时候,运行代码,报错如下:
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(),那么也会报错。
我们上面的代码显然两个问题都存在,所以报错是必然的。