关于java.lang.IllegalMonitorStateException

今天在写生产者消费者问题时,报出了关于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中已经有了解释

关于java.lang.IllegalMonitorStateException_第1张图片


只有获得当前锁的对象才可以调用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;
	}



比如用变量当锁,然后在同步块中对变量改变了值。抛出了java.lang.IllegalMonitorStateException。


真正的原因是在调用

this.wait = true;

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

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

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



参考资料:

1.http://blog.csdn.net/historyasamirror/article/details/6709693

2.http://www.blogjava.net/freeman1984/archive/2011/10/14/361306.html

你可能感兴趣的:(java,synchronized)