java synchronized boolean_使用Boolean类型同步锁引起异常的分析

本文分析了一段Java代码中出现的IllegalMonitorStateException异常原因,并提供了两种解决方案:一是利用Boolean对象的特殊性,二是使用可变对象作为锁。通过这两种方法避免了因同步锁对象在通知线程前被更改而导致的问题。

publicclassMyTest {

publicstaticvoidmain(String[] args)throwsException {

newTestThread().start();

newTestThread().start();

Thread.sleep(1000);

System.out.println("Doing something...");

synchronized(lock) {

lock =false;// 语句1

lock.notifyAll();// 语句2

}

}

staticvolatileBoolean lock =true;

}

classTestThreadextendsThread {

@Override

publicvoidrun() {

synchronized(MyTest.lock) {

while(MyTest.lock) {

try{

MyTest.lock.wait();

}catch(InterruptedException e) {

e.printStackTrace();

}

}

System.out.println(getId());

}

}

}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

}synchronized (lock) {

lock = false; // 语句1

lock.notifyAll(); // 语句2

}

语句1那里修改了lock的对象指向,结果造成下面的一句notifyAll使用了一个并没有synchronized的对象,随意报出了异常。

解决方法

方案1,使用Boolean的特殊性 由于 lock=false;的特殊性,分析Boolean的源代码发现

publicstaticfinalBoolean TRUE =newBoolean(true);

publicstaticfinalBoolean FALSE =newBoolean(false);

publicstaticBoolean valueOf(booleanb) {

return(b ? TRUE : FALSE);

}

//发现其内部对于自动打包,拆包只使用了2个固定的对象。所以可以用

synchronized(lock) {

lock =false;// 语句1

Boolean.TRUE.notifyAll();// 语句2

}

// 直接使用那个TRUE就行了。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;

}

staticvolatileMyLock lock =newMyLock();static volatile MyLock lock = new MyLock();

// 然后再代码里面用

lock.lock=false;// 进行标志的变更和判断就可以了

结论:

同步锁最好单独使用,如果锁自身附带了其它作用,应使用一个可变的对象 推荐

staticvolatileMyLock lock =newMyLock();static volatile MyLock lock = new MyLock();应该写成

finalstaticvolatileMyLock lock =newMyLock();final static volatile MyLock lock = new MyLock();

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值