java并发编程(2)——wait和notify解析

原创
2014/04/12 14:04
阅读数 1.3K

   JAVA的进程同步是通过synchronized()来实现的,需要说明的是,JAVA的synchronized()方法类似于操作系统概念中的互斥内存块,在JAVA中的Object类型中,都是带有一个内存锁的,在有线程获取该内存锁后,其它线程无法访问该内存,从而实现JAVA中简单的同步、互斥操作。明白这个原理,就能理解为什么synchronized(this)与synchronized(static XXX)的区别了,synchronized就是针对内存区块申请内存锁,this关键字代表类的一个对象,所以其内存锁是针对相同对象的互斥操作,而static成员属于类专有,其内存空间为该类所有成员共有,这就导致synchronized()对static成员加锁,相当于对类加锁,也就是在该类的所有成员间实现互斥,在同一时间只有一个线程可访问该类的实例。如果只是简单的想要实现在JAVA中的线程互斥,明白这些基本就已经够了。但如果需要在线程间相互唤醒的话就需要借助Object.wait(), Object.nofity()了。


wait与notify是java同步机制中重要的组成部分。结合与synchronized关键字使用,可以建立很多优秀的同步模型。
     synchronized(this){}等价与public synchronized void method(){.....}
     同步分为类级别和对象级别,分别对应着类锁和对象锁
类锁是每个类只有一个,如果static的方法被synchronized关键字修饰则在这个方法被执行前必须获得类锁;对象锁类同。(static synchronized是类级别的,非static的synchronized和synchronized块都是对象级别的,即作用在同一new出来的对象上)
     首先,调用一个Object的wait与notify/notifyAll的时候,必须保证调用代码对该Object是同步的,也就是说必须在作用等同于synchronized(obj){......}的内部才能够去调用obj的wait与notify/notifyAll三个方法,否则就会报错:
     java.lang.IllegalMonitorStateException: current thread not owner
     在调用wait的时候,线程自动释放其占有的对象锁,同时不会去申请对象锁。当线程被唤醒的时候,它才再次获得了去获得对象锁的权利。
     所以,notify与notifyAll没有太多的区别,只是notify仅唤醒一个线程并允许它去获得锁,notifyAll是唤醒所有等待这个对象的线程并允许它们去获得对象锁,只要是在synchronied块中的代码,没有对象锁是寸步难行的。其实唤醒一个线程就是重新允许这个线程去获得对象锁并向下运行。
       顺便说一下notifyall,虽然是对每个wait的对象都调用一次notify,但是这个还是有顺序的,每个对象都保存这一个等待对象链,调用的顺序就是这个链的顺序。其实启动等待对象链中各个线程的也是一个线程,在具体应用的时候,需要注意一下。


应用实例:

建立三个线程,A线程打印10次A,B线程打印10次B,C线程打印10次C,要求线程同时运行,交替打印10次ABC。这个问题用Object的wait(),notify()就可以很方便的解决。


package cn.com.thread;

/**
 * Description: <交替打印10次ABC>. <br>
 * <p>
 * <使用说明>
 * </p>
 * Makedate:2014-4-12 下午2:14:19
 * 
 * @author gaowenming
 * @version V1.0
 */
public class WaitAndNotifyTest {

	/**
	 * 描述 : <描述函数实现的功能>. <br>
	 * <p>
	 * <使用方法说明>
	 * </p>
	 * 
	 * @param args
	 */
	public static void main(String[] args) {

		final PrintABC printAbc = new PrintABC();

		// 循环加载外层
		for (int i = 0; i < 10; i++) {
			new Thread(new Runnable() {
				@Override
				public void run() {
					try {
						printAbc.printA(); // printA
					} catch (Exception e) {
						e.printStackTrace();
					}

				}
			}).start();

			new Thread(new Runnable() {
				@Override
				public void run() {
					try {
						printAbc.printB();// printB
					} catch (Exception e) {
						e.printStackTrace();
					}

				}
			}).start();

			new Thread(new Runnable() {
				@Override
				public void run() {
					try {
						printAbc.printC();// printC
					} catch (Exception e) {
						e.printStackTrace();
					}

				}
			}).start();

		}

	}

}

/**
 * 
 * 
 * @Description: 交替打印10次ABC
 * @author gaowenming
 * @date 2014-4-12 下午2:17:11
 * 
 */
class PrintABC {
	// 定义全局变量
	boolean a = true;
	boolean b = false;
	boolean c = false;

	public synchronized void printA() throws Exception {
		// 用while,表示一直等待
		while (!a) {
			this.wait();
		}
		System.out.print("A");
		a = false;
		b = true;

		// 执行完后唤醒其他等待的线程
		notifyAll();

	}

	public synchronized void printB() throws Exception {
		while (!b) {
			this.wait();
		}
		System.out.print("B");
		b = false;
		c = true;
		notifyAll();
	}

	public synchronized void printC() throws Exception {
		while (!c) {
			this.wait();
		}
		System.out.println("C");
		c = false;
		a = true;
		notifyAll();
	}
}


运行结果:

ABC

ABC

ABC

ABC

ABC

ABC

ABC

ABC

ABC

ABC


展开阅读全文
打赏
0
7 收藏
分享
加载中
更多评论
打赏
0 评论
7 收藏
0
分享
返回顶部
顶部