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