原文地址 http://topic.youkuaiyun.com/u/20080710/19/f61cb4db-ddff-4457-a26a-4ea578b0cc6c.html?87447500 http://www.java2000.net/viewthread.jsp?tid=7085
提问:【tteesstt】
public class MyTest {
public static void main(String[] args) throws Exception {
new TestThread().start();
new TestThread().start();
Thread.sleep(1000);
System.out.println("Doing something...");
synchronized (lock) {
lock = false; // 语句1
lock.notifyAll(); // 语句2
}
}
static volatile Boolean lock = true;
}
class TestThread extends Thread {
@Override
public void run() {
synchronized (MyTest.lock) {
while (MyTest.lock) {
try {
MyTest.lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(getId());
}
}
}
输出结果为
synchronized (lock) {
lock = false; // 语句1
lock.notifyAll(); // 语句2
}
语句1那里修改了lock的对象指向,结果造成下面的一句notifyAll使用了一个并没有synchronized的对象,随意报出了异常。
解决方法
方案1,使用Boolean的特殊性 由于 lock=false;的特殊性,分析Boolean的源代码发现
public static final Boolean TRUE = new Boolean(true);
public static final Boolean FALSE = new Boolean(false);
public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE);
}
//发现其内部对于自动打包,拆包只使用了2个固定的对象。所以可以用
synchronized (lock) {
lock = false; // 语句1
Boolean.TRUE.notifyAll(); // 语句2
}
// 直接使用那个TRUE就行了。
方法2:使用一个参数可变对象,而不是不可变的,
比如
class MyLock {
boolean lock = true;
}
static volatile MyLock lock = new MyLock();
// 然后再代码里面用
lock.lock=false;// 进行标志的变更和判断就可以了
结论:
同步锁最好单独使用,如果锁自身附带了其它作用,应使用一个可变的对象 推荐
static volatile MyLock lock = new MyLock(); 应该写成
final static volatile MyLock lock = new MyLock();
<script type="text/javascript"> </script> <script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"> </script>
本文分析了一段Java代码中出现的IllegalMonitorStateException异常原因,并给出了两种解决方案。异常源于同步锁对象在等待通知过程中被修改,导致未获得锁的线程尝试调用notifyAll方法。
1144

被折叠的 条评论
为什么被折叠?



