1. 线程的等待或者唤醒,并不是让线程调用自己的wait或者notify方法,而是通过调用线程共享对象的wait或者notify方法来实现。 2. 线程要调用某个对象的wait或者notify方法,必须先取得该对象的监视器(锁)。 3. 线程的协作必须以线程的互斥为前提,这种协作实际上是一种互斥下的协作。


 

 


举个例子: 有一家汉堡店举办吃汉堡比赛,决赛时有3个顾客来吃,3个厨师来做,一个服务员负责协调汉堡的数量。 为了避免浪费,制作好的汉堡被放进一个能装有10个汉堡的长条状容器中,按照先进先出的原则取汉堡。 如果容器被装满,则厨师停止做汉堡,如果顾客发现容器内的汉堡吃完了,就可以拍响容器上的闹铃, 提醒厨师再做几个汉堡出来。此时服务员过来安抚顾客,让他等待。而一旦厨师的汉堡做出来,就会让服务员 通知顾客,汉堡做好了,让顾客继续过来取汉堡。 这里,顾客其实就是我们所说的消费者,而厨师就是生产者。容器是决定厨师行为的监视器, 而服务员则负责监视顾客的行为。


 

 

服务员: Waiter

    

public class Waiter {

	/**
	 * <p>Title: Waiter</p>
	 * <p>Description: 服务员类的默认构造方法</p>
	 */
	public Waiter(){}
}

 

汉堡: Hamberg

  

/**
 * @ClassName: Hamberg
 * @Description: 汉堡
 * @author 
 * @date 2011-8-19
 * @version V1.0
 */
public class Hamberg {

	// 汉堡编号
	private int id;

	// 厨师编号
	private String cookerid;

	/**
	 * <p>
	 * Title: Hamberg
	 * </p>
	 * <p>
	 * Description: 汉堡类的构造方法
	 * </p>
	 * 
	 * @param id
	 *            汉堡编号
	 * @param cookerid
	 *            厨师编号
	 */
	public Hamberg(int id, String cookerid) {
		this.id = id;
		this.cookerid = cookerid;
	}

	public String toString() {

		StringBuffer buf = new StringBuffer("");

		buf.append("#").append(id).append(" cooked by ").append(cookerid);

		return buf.toString();
	}
}

 

汉堡容器: HambergFifo

   

/**
 * @ClassName: HambergFifo
 * @Description: 汉堡容器
 * @author 
 * @date 2011-8-19
 * @version V1.0
 */
public class HambergFifo {

	// 借助ArrayList来存放汉堡包
	List<Hamberg> hambergs = new ArrayList<Hamberg>(10);

	// 指定容器的容量
	public static final int MAX_SIZE = 10;

	/**
	 * @Title: push
	 * @Description: 放入汉堡
	 * @param t
	 *            : 要放入的汉堡
	 * @author 
	 */
	public <T extends Hamberg> void push(T t) {
		hambergs.add(t);
	}

	/**
	 * @Title: pop
	 * @Description: 取出汉堡
	 * @return Hamberg 汉堡
	 * @author 
	 */
	public Hamberg pop() {
		/**
		 * 每次取出一个,
		 * 由于是先进先出,所以取出的必是第一个
		 */
		Hamberg h = hambergs.get(0);
		hambergs.remove(h);
		return h;
	}

	/**
	 * @Title: isEmpty
	 * @Description: 判断容器是否为空
	 * @return boolean
	 * @author 
	 */
	public synchronized boolean isEmpty() {
		return hambergs.isEmpty();
	}

	/**
	 * @Title: size
	 * @Description: 容器内汉堡的个数
	 * @return int
	 * @author 
	 */
	public synchronized int size() {
		return hambergs.size();
	}

	/**
	 * @Title: maxSize
	 * @Description: 返回容器的最大容量
	 * @return int
	 * @author 
	 */
	public synchronized int maxSize() {
		return MAX_SIZE;
	}

	/**
	 * @Title: isNotFull
	 * @Description: 判断容器是否已满,未满为真
	 * @return boolean
	 * @author 
	 */
	public synchronized boolean isNotFull() {
		return hambergs.size() < MAX_SIZE;
	}
}

 

 

厨师 : Cooker

  

/**
 * @ClassName: Cooker
 * @Description: 厨师
 * @author 
 * @date 2011-8-19
 * @version V1.0
 */
public class Cooker implements Runnable {

	// 厨师要面对服务生
	private Waiter waiter;

	// 还要面对汉堡容器
	private HambergFifo pool;

	public Cooker(Waiter waiter, HambergFifo pool) {
		this.waiter = waiter;
		this.pool = pool;
	}

	public void run() {
		makeHamberg();
	}

	/**
	 * @Title: makeHamberg
	 * @Description: 厨师制作汉堡
	 * @author 
	 */
	private void makeHamberg() {

		// 制造的个数
		int madeCount = 0;

		// 因为容器满,被迫等待的次数
		int fullFiredCount = 0;

		try {

			Hamberg h = null;

			while (true) {
				// 制作汉堡前的准备工作
				Thread.sleep(1000);

				// 如果容器不为空
				if (pool.isNotFull()) {

					synchronized (waiter) {
						// 制作汉堡,并放入容器
						h = new Hamberg(++madeCount, Thread.currentThread()
								.getName());
						pool.push(h);

						System.out.println(Thread.currentThread().getName()
								+ ":There are " + pool.size()
								+ " Hambergs in all");

						// 让服务生通知顾客,有汉堡可以吃了
						waiter.notifyAll();

						System.out.println("### Cooker: waiter.notifyAll() :"
								+ " Hi! Customers, we got some new Hambergs!");
					}
				} else {
					/* 发现容器满了,停止做汉堡的尝试 */

					synchronized (pool) {

						if (fullFiredCount < HambergFifo.MAX_SIZE) {

							System.out
									.println(Thread.currentThread().getName()
											+ ": Hamberg Pool is Full, Stop making hamberg");

							System.out.println("### Cooker: pool.wait()");

							// 汉堡容器的状况使厨师等待
							pool.wait();
						} else {
							return;
						}
					}
				}
				// 做完汉堡要进行收尾工作,为下一次的制作做准备。
				Thread.sleep(1000);
			}

		} catch (InterruptedException e) {
			fullFiredCount--;
			e.printStackTrace();
		}
	}
}

 

顾客: Customer

  

/**
 * @ClassName: Customer
 * @Description: 顾客
 * @author 
 * @date 2011-8-19
 * @version V1.0
 */
public class Customer implements Runnable {

	// 顾客要面对服务生
	Waiter waiter;

	// 也要面对汉堡包容器
	HambergFifo pool;

	// 想要记下自己吃了多少汉堡
	int ateCount = 0;

	// 吃每个汉堡的时间不尽相同
	long sleeptime;

	// 用于产生随机数
	Random r = new Random();

	public Customer(Waiter waiter, HambergFifo pool) {
		this.waiter = waiter;
		this.pool = pool;
	}

	public void run() {

		while (true) {
			try {
				getHamberg();
				eatHamberg();
			} catch (Exception e) {
				// 若取不到汉堡,要和服务生打交道
				synchronized (waiter) {

					System.out.println(e);

					try {
						System.out
								.println("### Customer: waiter.wait():"
										+ " Sorry, Sir, there is no hambergs left, please wait!");
						System.out.println(Thread.currentThread().getName()
								+ ": OK, Waiting for new hambergs");
						// 服务生安抚顾客,让他等待。
						waiter.wait();
						continue;
					} catch (InterruptedException ex) {
						ex.printStackTrace();
					}
				}
			}
		}
	}

	/**
	 * @Title: getHamberg
	 * @Description: 取出汉堡
	 * @author 
	 */
	private void getHamberg() throws Exception {

		synchronized (pool) {
			try {
				// 在容器内取汉堡
				Hamberg hamberg = pool.pop();

				ateCount++;

				System.out.println(Thread.currentThread().getName()
						+ ": I Got " + ateCount + " Hamberg " + hamberg);
				System.out
						.println(Thread.currentThread().getName()
								+ ": There are still " + pool.size()
								+ " hambergs left");
			} catch (Exception e) {

				pool.notifyAll();

				StringBuffer msg = new StringBuffer("");

				msg.append(": OH MY GOD!!!! No hambergs left, Waiter!").append(
						"[Ring the bell besides the hamberg pool]");

				throw new Exception(Thread.currentThread().getName()
						+ msg.toString());
			}
		}
	}

	/**
	 * @Title: eatHamberg
	 * @Description: 吃汉堡
	 * @author 
	 */
	private void eatHamberg() {

		try {
			// 吃每个汉堡的时间不等
			sleeptime = Math.abs((r.nextInt(3000))) * 5;

			System.out.println(Thread.currentThread().getName()
					+ ": I'm eating the hamberg for " + sleeptime
					+ " milliseconds");

			Thread.sleep(sleeptime);

		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

 

测试类: HambergShop

   

public class HambergShop {

	Waiter waiter = new Waiter();

	HambergFifo hambergPool = new HambergFifo();

	Customer c1 = new Customer(waiter, hambergPool);
	Customer c2 = new Customer(waiter, hambergPool);
	Customer c3 = new Customer(waiter, hambergPool);

	Cooker cooker = new Cooker(waiter, hambergPool);

	/**
	 * @Title: main
	 * @Description: 测试方法
	 * @param args
	 * @author 
	 */
	public static void main(String[] args) {

		HambergShop shop = new HambergShop();

		Thread t1 = new Thread(shop.c1, "Customer1");
		Thread t2 = new Thread(shop.c2, "Customer2");
		Thread t3 = new Thread(shop.c3, "Customer3");

		Thread t4 = new Thread(shop.cooker, "Cooker 1");
		Thread t5 = new Thread(shop.cooker, "Cooker 2");
		Thread t6 = new Thread(shop.cooker, "Cooker 3");

		t4.start();
		t5.start();
		t6.start();

		try {
			Thread.sleep(10000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		t1.start();
		t2.start();
		t3.start();
	}

}

 

测试结果:

  


Cooker 1:There are 1 Hambergs in all
### Cooker: waiter.notifyAll() : Hi! Customers, we got some new Hambergs!
Cooker 3:There are 2 Hambergs in all
### Cooker: waiter.notifyAll() : Hi! Customers, we got some new Hambergs!
Cooker 2:There are 3 Hambergs in all
### Cooker: waiter.notifyAll() : Hi! Customers, we got some new Hambergs!
Cooker 2:There are 4 Hambergs in all
### Cooker: waiter.notifyAll() : Hi! Customers, we got some new Hambergs!
Cooker 3:There are 5 Hambergs in all
### Cooker: waiter.notifyAll() : Hi! Customers, we got some new Hambergs!
Cooker 1:There are 6 Hambergs in all
### Cooker: waiter.notifyAll() : Hi! Customers, we got some new Hambergs!
Cooker 3:There are 7 Hambergs in all
### Cooker: waiter.notifyAll() : Hi! Customers, we got some new Hambergs!
Cooker 1:There are 8 Hambergs in all
### Cooker: waiter.notifyAll() : Hi! Customers, we got some new Hambergs!
Cooker 2:There are 9 Hambergs in all
### Cooker: waiter.notifyAll() : Hi! Customers, we got some new Hambergs!
Cooker 3:There are 10 Hambergs in all
### Cooker: waiter.notifyAll() : Hi! Customers, we got some new Hambergs!
Cooker 2: Hamberg Pool is Full, Stop making hamberg
### Cooker: pool.wait()
Cooker 1: Hamberg Pool is Full, Stop making hamberg
### Cooker: pool.wait()
Cooker 3: Hamberg Pool is Full, Stop making hamberg
### Cooker: pool.wait()
Customer1: I Got 1 Hamberg #1 cooked by Cooker 1
Customer1: There are still 9 hambergs left
Customer3: I Got 1 Hamberg #1 cooked by Cooker 3
Customer1: I'm eating the hamberg for 7285 milliseconds
Customer3: There are still 8 hambergs left
Customer3: I'm eating the hamberg for 4405 milliseconds
Customer2: I Got 1 Hamberg #1 cooked by Cooker 2
Customer2: There are still 7 hambergs left
Customer2: I'm eating the hamberg for 3170 milliseconds
Customer2: I Got 2 Hamberg #2 cooked by Cooker 2
Customer2: There are still 6 hambergs left
Customer2: I'm eating the hamberg for 6200 milliseconds
Customer3: I Got 2 Hamberg #2 cooked by Cooker 3
Customer3: There are still 5 hambergs left
Customer3: I'm eating the hamberg for 1260 milliseconds
Customer3: I Got 3 Hamberg #2 cooked by Cooker 1
Customer3: There are still 4 hambergs left
Customer3: I'm eating the hamberg for 5045 milliseconds
Customer1: I Got 2 Hamberg #3 cooked by Cooker 3
Customer1: There are still 3 hambergs left
Customer1: I'm eating the hamberg for 5835 milliseconds
Customer2: I Got 3 Hamberg #3 cooked by Cooker 1
Customer2: There are still 2 hambergs left
Customer2: I'm eating the hamberg for 3255 milliseconds
Customer3: I Got 4 Hamberg #3 cooked by Cooker 2
Customer3: There are still 1 hambergs left
Customer3: I'm eating the hamberg for 8265 milliseconds
Customer2: I Got 4 Hamberg #4 cooked by Cooker 3
Customer2: There are still 0 hambergs left
Customer2: I'm eating the hamberg for 5525 milliseconds
java.lang.Exception: Customer1: OH MY GOD!!!! No hambergs left, Waiter![Ring the bell besides the hamberg pool]
### Customer: waiter.wait(): Sorry, Sir, there is no hambergs left, please wait!
Customer1: OK, Waiting for new hambergs
Cooker 2:There are 1 Hambergs in all
### Cooker: waiter.notifyAll() : Hi! Customers, we got some new Hambergs!
Cooker 1:There are 2 Hambergs in all
### Cooker: waiter.notifyAll() : Hi! Customers, we got some new Hambergs!
Cooker 3:There are 3 Hambergs in all
### Cooker: waiter.notifyAll() : Hi! Customers, we got some new Hambergs!
Customer1: I Got 3 Hamberg #4 cooked by Cooker 2
Customer1: There are still 2 hambergs left
Customer1: I'm eating the hamberg for 14410 milliseconds
Cooker 2:There are 3 Hambergs in all
### Cooker: waiter.notifyAll() : Hi! Customers, we got some new Hambergs!
Cooker 3:There are 4 Hambergs in all
### Cooker: waiter.notifyAll() : Hi! Customers, we got some new Hambergs!
Cooker 1:There are 5 Hambergs in all
### Cooker: waiter.notifyAll() : Hi! Customers, we got some new Hambergs!
Customer2: I Got 5 Hamberg #4 cooked by Cooker 1
Customer2: There are still 4 hambergs left
Customer2: I'm eating the hamberg for 6620 milliseconds
Customer3: I Got 5 Hamberg #5 cooked by Cooker 3
Customer3: There are still 3 hambergs left
Customer3: I'm eating the hamberg for 14530 milliseconds
Cooker 1:There are 4 Hambergs in all
### Cooker: waiter.notifyAll() : Hi! Customers, we got some new Hambergs!
Cooker 3:There are 5 Hambergs in all
### Cooker: waiter.notifyAll() : Hi! Customers, we got some new Hambergs!
Cooker 2:There are 6 Hambergs in all
### Cooker: waiter.notifyAll() : Hi! Customers, we got some new Hambergs!
Cooker 2:There are 7 Hambergs in all
### Cooker: waiter.notifyAll() : Hi! Customers, we got some new Hambergs!
Cooker 1:There are 8 Hambergs in all
### Cooker: waiter.notifyAll() : Hi! Customers, we got some new Hambergs!
Cooker 3:There are 9 Hambergs in all
### Cooker: waiter.notifyAll() : Hi! Customers, we got some new Hambergs!
Cooker 2:There are 10 Hambergs in all
### Cooker: waiter.notifyAll() : Hi! Customers, we got some new Hambergs!
Cooker 1: Hamberg Pool is Full, Stop making hamberg
### Cooker: pool.wait()
Cooker 3: Hamberg Pool is Full, Stop making hamberg
### Cooker: pool.wait()
Customer2: I Got 6 Hamberg #5 cooked by Cooker 2
Customer2: There are still 9 hambergs left
Customer2: I'm eating the hamberg for 7865 milliseconds
Cooker 2:There are 10 Hambergs in all
### Cooker: waiter.notifyAll() : Hi! Customers, we got some new Hambergs!
Cooker 2: Hamberg Pool is Full, Stop making hamberg
### Cooker: pool.wait()
Customer1: I Got 4 Hamberg #6 cooked by Cooker 3
Customer1: There are still 9 hambergs left
Customer1: I'm eating the hamberg for 7460 milliseconds
Customer2: I Got 7 Hamberg #5 cooked by Cooker 1
Customer2: There are still 8 hambergs left
Customer2: I'm eating the hamberg for 5680 milliseconds
Customer3: I Got 6 Hamberg #6 cooked by Cooker 1
Customer3: There are still 7 hambergs left
Customer3: I'm eating the hamberg for 940 milliseconds
Customer3: I Got 7 Hamberg #7 cooked by Cooker 3
Customer3: There are still 6 hambergs left
Customer3: I'm eating the hamberg for 4880 milliseconds
Customer1: I Got 5 Hamberg #6 cooked by Cooker 2
Customer1: There are still 5 hambergs left
Customer1: I'm eating the hamberg for 1400 milliseconds
Customer2: I Got 8 Hamberg #7 cooked by Cooker 2
Customer2: There are still 4 hambergs left
Customer2: I'm eating the hamberg for 2955 milliseconds
Customer1: I Got 6 Hamberg #7 cooked by Cooker 1
Customer1: There are still 3 hambergs left
Customer1: I'm eating the hamberg for 5305 milliseconds
Customer3: I Got 8 Hamberg #8 cooked by Cooker 3
Customer3: There are still 2 hambergs left
Customer3: I'm eating the hamberg for 12830 milliseconds
Customer2: I Got 9 Hamberg #8 cooked by Cooker 2
Customer2: There are still 1 hambergs left
Customer2: I'm eating the hamberg for 14400 milliseconds
Customer1: I Got 7 Hamberg #9 cooked by Cooker 2
Customer1: There are still 0 hambergs left
Customer1: I'm eating the hamberg for 7720 milliseconds
java.lang.Exception: Customer1: OH MY GOD!!!! No hambergs left, Waiter![Ring the bell besides the hamberg pool]
### Customer: waiter.wait(): Sorry, Sir, there is no hambergs left, please wait!
Customer1: OK, Waiting for new hambergs
java.lang.Exception: Customer3: OH MY GOD!!!! No hambergs left, Waiter![Ring the bell besides the hamberg pool]
### Customer: waiter.wait(): Sorry, Sir, there is no hambergs left, please wait!
Customer3: OK, Waiting for new hambergs
Cooker 3:There are 1 Hambergs in all
### Cooker: waiter.notifyAll() : Hi! Customers, we got some new Hambergs!
Cooker 1:There are 2 Hambergs in all
### Cooker: waiter.notifyAll() : Hi! Customers, we got some new Hambergs!
Cooker 2:There are 3 Hambergs in all
### Cooker: waiter.notifyAll() : Hi! Customers, we got some new Hambergs!
Customer1: I Got 8 Hamberg #9 cooked by Cooker 3
Customer1: There are still 2 hambergs left
Customer1: I'm eating the hamberg for 8995 milliseconds
Customer3: I Got 9 Hamberg #8 cooked by Cooker 1
Customer3: There are still 1 hambergs left
Customer3: I'm eating the hamberg for 5240 milliseconds
Cooker 1:There are 2 Hambergs in all
### Cooker: waiter.notifyAll() : Hi! Customers, we got some new Hambergs!
Cooker 2:There are 3 Hambergs in all
### Cooker: waiter.notifyAll() : Hi! Customers, we got some new Hambergs!
Cooker 3:There are 4 Hambergs in all
### Cooker: waiter.notifyAll() : Hi! Customers, we got some new Hambergs!
Customer2: I Got 10 Hamberg #10 cooked by Cooker 2
Customer2: There are still 3 hambergs left
Customer2: I'm eating the hamberg for 10590 milliseconds