synchronized 与IllegalMonitorStateException异常

来看一个面试题目

在子线程中执行一段代码10次,然后在主线程中执行代码50次,然后再在子线程中执行代码10次,然后是主线程....这样循环50次,应该如何实现

这个题目考验的是线程的互斥和通信,互斥就是加一个锁,通信就是设置一个共享的值,我以为很简单就用下面的代码实现

<pre name="code" class="java">package day20150802;

import org.junit.Test;

public class CopyOfMainAndSubThreadTest2 {
	private final static Object Monitor = new Object();
	private static boolean first = false;
	private static boolean control = true;
	@Test
	public  void main()  {
			final Run run = new Run();
			new Thread(new Runnable() {
			public void run() {
				for(int sub = 0;sub<50;sub++){
					run.sub(sub);
				}
			}
		} ).start();
		for(int sub = 0;sub<50;sub++){
			run.main(sub);
		}
	}
}
class Run{
	private final Object Monitor = new Object();
	private boolean control =true;
	
	public  void main(int j){
		synchronized(this.Monitor){
		while(!control){
			try {
				wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
			for(int i = 0;i<50;i++)
			System.out.println("main "+(j+1)+"--"+(i+1));
			control=false;
			
	}
		notify();
	}
	public  void sub(int sub) {
		synchronized(this.Monitor){
		while(control){
			try {
				wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				System.out.println(e);
				e.printStackTrace();
			}
		}
		for(int i = 0;i<10;i++){
			System.out.println("sub "+(sub+1)+"--"+(i+1));
		}
		control=true;
	}
		this.notify();
	}
}

 执行结果: 

[Console output redirected to file:C:\Myeclipse\MyEclipse 10\OutPutTest.JavaTestOutTxt]

 main 1--1

 main 1--2

 main 1--3

 main 1--4 

main 1--5

 main 1--6

.....

  main 1--49

 main 1--50 

sub 1--1 

sub 1--2 

sub 1--3 

sub 1--4 

sub 1--5 

sub 1--6 

sub 1--7

 sub 1--8

 sub 1--9

 sub 1--10

 Exception in thread "Thread-0" java.lang.IllegalMonitorStateException 

at java.lang.Object.notify(Native Method)at day20150802.Run.sub(CopyOfMainAndSubThreadTest2.java:61) 

at day20150802.CopyOfMainAndSubThreadTest2$1.run(CopyOfMainAndSubThreadTest2.java:15) 

at java.lang.Thread.run(Thread.java:619)

而把 synchronized 锁加到 方法上面就可以运行了,代码如下

<pre name="code" class="java">package day20150802;

import org.junit.Test;

public class CopyOfMainAndSubThreadTest2 {
	private final static Object Monitor = new Object();
	private static boolean first = false;
	private static boolean control = true;
	@Test
	public  void main()  {
			final Run run = new Run();
			new Thread(new Runnable() {
			public void run() {
				for(int sub = 0;sub<50;sub++){
					run.sub(sub);
				}
			}
		} ).start();
		for(int sub = 0;sub<50;sub++){
			run.main(sub);
		}
	}
}
class Run{
	private final Object Monitor = new Object();
	private boolean control =true;
	
	public synchronized  void main(int j){
		
		while(!control){
			try {
				this.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
			for(int i = 0;i<50;i++)
			System.out.println("main "+(j+1)+"--"+(i+1));
			control=false;
			this.notifyAll();
	}
	public synchronized void sub(int sub) {
		while(control){
			try {
				this.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				System.out.println(e);
				e.printStackTrace();
			}
		}
		for(int i = 0;i<10;i++){
			System.out.println("sub "+(sub+1)+"--"+(i+1));
		}
		control=true;
		this.notifyAll();
	}
}

 这是为什么?? 

这个异常是说,若不拥有对象的锁标记,而试图用wait/notify协调共享对象资源,应用程序将抛出IllegalMonitorStateException。

我看查询完资料后发现,synchronized是获取对象内部的锁,而我使用同步代码块的时候,获取的是Monitor的内部锁,而不是这个类的内部锁,所以,this.notify();改为this.Monitor.notify()就可以了

package day20150802;

import org.junit.Test;

public class CopyOfMainAndSubThreadTest2 {
	private final static Object Monitor = new Object();
	private static boolean first = false;
	private static boolean control = true;
	@Test
	public  void main()  {
			final Run run = new Run();
			new Thread(new Runnable() {
			public void run() {
				for(int sub = 0;sub<50;sub++){
					run.sub(sub);
				}
			}
		} ).start();
		for(int sub = 0;sub<50;sub++){
			run.main(sub);
		}
	}
}
class Run{
	private final Object Monitor = new Object();
	private boolean control =true;
	
	public  void main(int j){
		synchronized(this.Monitor){
		while(!control){
			try {
				this.Monitor.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
			for(int i = 0;i<50;i++)
			System.out.println("main "+(j+1)+"--"+(i+1));
			control=false;
			this.Monitor.notifyAll();
	}
		
	}
	public  void sub(int sub) {
		synchronized(this.Monitor){
		while(control){
			try {
				this.Monitor.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				System.out.println(e);
				e.printStackTrace();
			}
		}
		for(int i = 0;i<10;i++){
			System.out.println("sub "+(sub+1)+"--"+(i+1));
		}
		control=true;
		this.Monitor.notifyAll();
		}
	}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值