注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

_

_

 
 
 

日志

 
 

诡异的java.lang.IllegalMonitorStateException  

2014-11-21 09:37:02|  分类: 默认分类 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

诡异的java.lang.IllegalMonitorStateException

分类: JAVA 2011-08-22 20:39 7711人阅读 评论(3) 收藏 举报

javadocobjectthreadintegerstringclass

今天的一段代码抛出了java.lang.IllegalMonitorStateException,代码如下:

[java] view plaincopyprint?

  1. private boolean wait = false;?
  2. public boolean pleaseWait() {?
  3. synchronized (this.wait) {?
  4. if (this.wait == true) {?
  5. return false;?
  6. ??? }?
  7. this.wait =true;?
  8. try {?
  9. this.wait.wait();?
  10. ??? } catch (InterruptedException e) {?
  11. ??? }?
  12. return true;?
  13. }?
	private boolean wait = false;
	
	public boolean pleaseWait() {
	synchronized (this.wait) {
		if (this.wait == true) {
			return false;
		}

		this.wait =true;
		
		try {
			this.wait.wait();
		} catch (InterruptedException e) {

		}

		return true;
	}

JavaDoc上关于IllegalMonitorStateException的解释是:

Thrown to indicate that a thread has attempted to wait on an object's monitor or to notify other threads waiting on an object's monitor without owning the specified monitor.

看起来有些晦涩难懂,比如object's monitor。其实,在Object.notify()这个函数的JavaDoc中有相关的解释:

A thread becomes the owner of the object's monitor in one of three ways:
1. By executing a synchronized instance method of that object.
2. By executing the body of a synchronized statement that synchronizes on the object.
3. For objects of type Class, by executing a synchronized static method of that class.

说白了,就是需要在调用wait()或者notify()之前,必须使用synchronized语义绑定住被wait/notify的对象。

可问题是,在上面的代码中,已经对this.wait这个变量使用了synchronzied,然后才调用的this.wait.wait()。按理不应该抛出这个异常。

上网查了很久,终于找到了答案:

真正的问题在于this.wait这个变量是一个Boolean,并且,在调用this.wait.wait()之前,this.wait执行了一次赋值操作:

[java] view plaincopyprint?

  1. this.wait = true;?
this.wait = true;
Boolean型变量在执行赋值语句的时候,其实是创建了一个新的对象。简单的说,在赋值语句的之前和之后,this.wait并不是同一个对象。

synchronzied(this.wait)绑定的是旧的Boolean对象,而this.wait.wait()使用的是新的Boolean对象。由于新的Boolean对象并没有使用synchronzied进行同步,所以系统抛出了IllegalMonitorStateException异常。

相同的悲剧还有可能出现在this.wait是Integer或者String类型的时候。

一个解决方案是采用java.util.concurrent.atomic中对应的类型,比如这里就应该是AtomicBoolean。采用AtomicBoolean类型,可以保证对它的修改不会产生新的对象。

正确的代码:

[java] view plaincopyprint?

  1. private AtomicBoolean wait = new AtomicBoolean(false);?
  2. public boolean pleaseWait() {?
  3. synchronized (this.wait) {?
  4. if (this.wait.get() == true) {?
  5. return false;?
  6. ??????? }?
  7. this.wait.set(true);?
  8. try {?
  9. this.wait.wait();?
  10. ??????? } catch (InterruptedException e) {?
  11. ??????? }?
  12. return true;?
  13. ??? }?
  14. }?
  评论这张
 
阅读(204)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017