Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1661427
  • 博文数量: 695
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 4027
  • 用 户 组: 普通用户
  • 注册时间: 2013-11-20 21:22
文章分类

全部博文(695)

文章存档

2018年(18)

2017年(74)

2016年(170)

2015年(102)

2014年(276)

2013年(55)

分类: Java

2017-11-08 21:56:06

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

点击(此处)折叠或打开

  1. private boolean wait = false;
  2.     
  3.     public boolean pleaseWait() {
  4.     synchronized (this.wait) {
  5.         if (this.wait == true) {
  6.             return false;
  7.         }

  8.         this.wait =true;
  9.         
  10.         try {
  11.             this.wait.wait();
  12.         } catch (InterruptedException e) {

  13.         }

  14.         return true;
  15.     }

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 plain copy
  1. 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类型,可以保证对它的修改不会产生新的对象。

正确的代码:

点击(此处)折叠或打开

  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.         }

阅读(1156) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~