原文地址 http://topic.csdn.net/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());
- }
- }
- }
输出结果为
Doing something...
Exception in thread "main" java.lang.IllegalMonitorStateException
at java.lang.Object.notifyAll(Native Method)
at MyTest.test(MyTest.java:13)
at MyTest.main(MyTest.java:3
如果把语句1和语句2调换一下就正常了。 大家给诊断一下,到底是为什么?
讨论过程请大家自行参考原始的帖子和我的整理帖子,这里只给出最终的分析结果
分析:
当作为同步锁的对象发生改变时,比如换了一个新的对象,那么如果在新的对象上调用同步的wait等方法,由于并没有同步这个对象,而是同步的改变以前的那个,就会报出如上的异常。 我们来看代码
- 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" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script>