线程间协作——wait、notify摘要

wait()、notify是定义在Object中的方法,用来控制线程间的协作。

  • wait方法:使持有该对象的线程把该对象的控制权(也就是锁,java api文档中称之为monitor)交出去,然后处于等待状态。
  • notify方法:就会通知某个正在等待这个对象的控制权的线程可以继续运行。


注意:
1.任何一个时刻,对象的锁(monitor)只能被一个线程拥有。
2.无论是执行对象的wait、notify还是notifyAll方法,必须保证当前运行的线程取得了该对象的锁(monitor)。这意味着调用wait、notify必須在synchronized 方法中,否则在运行期一定会抛出java.lang.IllegalMonitorStateException异常。
3.锁(monitor)可以是对象,也可是一个普通变量。线程间的同步协作必须要保证拿到的锁是同一个对象的引用。如果是以一个普通变量(例如一个boolean的flag),则有可能在运行期间被改变值,而导致线程拿到的不是同一把锁,导致不可预料的问题或抛出java.lang.IllegalMonitorStateException异常。

下面以大家所熟知的生产者与消费者问题的代码来说明wait、notify这两个方法的用法。

public class ProducerConsumer {

	public static void main(String[] args) {
		WoTouStack stack = new WoTouStack();
		Producer producer = new Producer(stack);
		Consumer consumer = new Consumer(stack);
		new Thread(producer).start();
		new Thread(consumer).start();
	
	}

}

class WoTou{
	public int id;

	public WoTou(int id) {
		this.id = id;
	}

	@Override
	public String toString() {
		return "wotou " + id;
	}
	
}

/** 
 * 装窝头的容器类 
 * 
 * */
class WoTouStack{
	int pushcount,popcount = 0;  //生产,消费总计
	int size = 10;
	WoTou[] stack = new WoTou[size];
	int index = 0;
	
	/**
	 * 丢进一个窝头, 并使用notify通知消费者线程来消费
	 * 如果容器满了就通知生产线程等待。
	 * @param wt
	 */
	public synchronized void push(WoTou wt){
		stack[index] = wt;
		index++;
		System.out.println("生产了: " + wt);
		pushcount++;
		if(index == size){
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		this.notify();
	}
	
	/**
	 * 拿出一个窝头, 并使用notify通知生产者线程进行生产
	 * 如果容器空了就通知消费线程等待。
	 * @return
	 */
	public synchronized WoTou pop(){
		if(index < 1){
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		this.notify();
		index--;
		popcount++;
		System.out.println("消费了: " + stack[index]);
		return stack[index];
	}
	
}

/** 生产者 **/
class Producer implements Runnable {
	WoTouStack stack = null;
	public Producer(WoTouStack stack){
		this.stack = stack;
	}
	@Override
	public void run() {
		for (int i = 0; i < 20; i++) {
			WoTou wt = new WoTou(i);
			stack.push(wt);
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		System.out.println("共生产了" + stack.pushcount);
	}
}

/** 消费者 **/
class Consumer implements Runnable {
	WoTouStack stack = null;
	public Consumer(WoTouStack stack){
		this.stack = stack;
	}
	@Override
	public void run() {
		for (int i = 0; i < 20; i++) {
			stack.pop();
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		System.out.println("共消费了" + stack.popcount);
	}
}

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