今天的一段代码抛出了java.lang.IllegalMonitorStateException,代码如下:
class ThreadC implements Runnable{
Boolean falg;
public ThreadC(Boolean falg) {
this.falg = falg;
}
@Override
public void run() {
synchronized (falg){
for (int i = 1; i <= 1000; i++) {
if(i % 2 == 0 && i % 3 == 0 && i % 5 == 0 && i % 7 ==0){
try {
falg = true;//报错的地方
System.out.println(i+"睡眠!");
falg.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
falg.notify();
}
}
}
}
上网查了很久,终于找到了答案:
真正的问题在于falg这个变量是一个Boolean
falg = true;
Boolean型变量在执行赋值语句的时候,其实是创建了一个新的对象。简单的说,在赋值语句的之前和之后,falg并不是同一个对象。
synchronzied(falg)绑定的是旧的Boolean对象,而重新赋值后新的Boolean对象并没有使用synchronzied进行同步,所以系统抛出了IllegalMonitorStateException异常。
相同的悲剧还有可能出现在falg是Integer或者String类型的时候。
一个解决方案是采用java.util.concurrent.atomic中对应的类型,比如这里就应该是AtomicBoolean。采用AtomicBoolean类型,可以保证对它的修改不会产生新的对象。
正确的代码:
class ThreadC implements Runnable{
AtomicBoolean falg;
public ThreadC(AtomicBoolean falg) {
this.falg = falg;
}
@Override
public void run() {
synchronized (falg) {
for (int i = 1; i <= 1000; i++) {
if (i % 2 == 0 && i % 3 == 0 && i % 5 == 0 && i % 7 == 0) {
try {
falg.set(true);
System.out.println(i + "睡眠!");
falg.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
falg.notify();
}
}
}
}