今天在写生产者消费者问题时,报出了关于java.lang.IllegalMonitorStateException这个错误
代码如下:
package test;
public class Hosee
{
private static Integer count = 0;//注意点,被synchronized保护的对象通常是private
private final Integer FULL = 10;
private static String LOCK = "LOCK";
class Producer implements Runnable
{
@Override
public void run()
{
for (int i = 0; i < 10; i++)
{
try
{
Thread.sleep(3000);
}
catch (Exception e)
{
// TODO: handle exception
e.printStackTrace();
}
synchronized (LOCK)
{
while (count == FULL)
{
try
{
wait();
}
catch (Exception e)
{
// TODO: handle exception
e.printStackTrace();
}
}
count++;
System.out.println(Thread.currentThread().getName()+"生产者生产,目前总共有" + count);
notify();
}
}
}
}
class Consumer implements Runnable
{
@Override
public void run()
{
for (int i = 0; i < 10; i++)
{
try
{
Thread.sleep(3000);
}
catch (InterruptedException e1)
{
// TODO Auto-generated catch block
e1.printStackTrace();
}
synchronized (LOCK)
{
while (count == 0)
{
try
{
wait();
}
catch (Exception e)
{
// TODO: handle exception
e.printStackTrace();
}
}
count--;
System.out.println(Thread.currentThread().getName()+"消费者消费,目前总共有" + count);
notify();
}
}
}
}
public static void main(String[] args) throws Exception
{
Hosee hosee = new Hosee();
new Thread(hosee.new Producer()).start();
new Thread(hosee.new Consumer()).start();
new Thread(hosee.new Producer()).start();
new Thread(hosee.new Consumer()).start();
new Thread(hosee.new Producer()).start();
new Thread(hosee.new Consumer()).start();
new Thread(hosee.new Producer()).start();
new Thread(hosee.new Consumer()).start();
}
}
原因很简单,在jdk中已经有了解释
只有获得当前锁的对象才可以调用wait/notify/notifyAll,我们可以粗略的理解为,锁了哪个就用哪个对象调用wait/notify/notifyAll(如同jdk中的例子)
所以在我的代码中,只要改成
LOCK.wait();
LOCK.notify();
我们可以举几个简单的例子:
exapmle 1,锁定方法所属的实例对象:
public synchronized void method(){
//然后就可以调用:this.notify()...
//或者直接调用notify()...
}
exapmle 2,锁定方法所属的实例的Class:
public Class Test{
public static synchronized void method(){
//然后调用:Test.class.notify()...
}
}
exapmle 3,锁定其他对象:
public Class Test{
public Object lock = new Object();
public static void method(){
synchronized (lock) {
//需要调用 lock.notify();
}
}
}
代码如下:
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;
}
真正的原因是在调用
this.wait = true;
之后。Boolean型变量在执行赋值语句的时候,其实是创建了一个新的对象。简单的说,在赋值语句的之前和之后,this.wait并不是同一个对象。
相同的悲剧还有可能出现在this.wait是Integer或者String类型的时候。
一个解决方案是采用java.util.concurrent.atomic中对应的类型,比如这里就应该是AtomicBoolean。采用AtomicBoolean类型,可以保证对它的修改不会产生新的对象。
参考资料:
1.http://blog.youkuaiyun.com/historyasamirror/article/details/6709693
2.http://www.blogjava.net/freeman1984/archive/2011/10/14/361306.html