转载自:http://blog.csdn.net/ghsau/article/details/7433673
假设有这样一种情况,有一个盘子,盘子里只能放一个鸡蛋,A线程专门往盘子里放鸡蛋,如果盘子里有鸡蛋,则一直等到盘子里没鸡蛋,B线程专门从盘子里取鸡蛋,如果盘子里没鸡蛋,则一直等到盘子里有鸡蛋。这里盘子是一个互斥区,每次放鸡蛋是互斥的,每次取鸡蛋也是互斥的,A线程放鸡蛋,如果这时B线程要取鸡蛋,由于A没有释放锁,B线程处于等待状态,进入阻塞队列,放鸡蛋之后,要通知B线程取鸡蛋,B线程进入就绪队列,反过来,B线程取鸡蛋,如果A线程要放鸡蛋,由于B线程没有释放锁,A线程处于等待状态,进入阻塞队列,取鸡蛋之后,要通知A线程放鸡蛋,A线程进入就绪队列。我们希望当盘子里有鸡蛋时,A线程阻塞,B线程就绪,盘子里没鸡蛋时,A线程就绪,B线程阻塞,代码如下:
- import java.util.ArrayList;
- import java.util.List;
-
- public class Plate {
-
- List<Object> eggs = new ArrayList<Object>();
-
- public synchronized Object getEgg() {
- while (eggs.size() == 0) {
- try {
- wait();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- Object egg = eggs.get(0);
- eggs.clear();
- notify();
- System.out.println("拿到鸡蛋");
- return egg;
- }
-
- public synchronized void putEgg(Object egg) {
- while (eggs.size() > 0) {
- try {
- wait();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- eggs.add(egg);
- notify();
- System.out.println("放入鸡蛋");
- }
- static class AddThread implements Runnable {
- private Plate plate;
- private Object egg = new Object();
- public AddThread(Plate plate) {
- this.plate = plate;
- }
- public void run() {
- plate.putEgg(egg);
- }
- }
- static class GetThread implements Runnable {
- private Plate plate;
- public GetThread(Plate plate) {
- this.plate = plate;
- }
- public void run() {
- plate.getEgg();
- }
- }
- public static void main(String args[]) {
- Plate plate = new Plate();
- for(int i = 0; i < 10; i++) {
- new Thread(new AddThread(plate)).start();
- new Thread(new GetThread(plate)).start();
- }
- }
- }
输出结果:
- 放入鸡蛋
- 拿到鸡蛋
- 放入鸡蛋
- 拿到鸡蛋
- 放入鸡蛋
- 拿到鸡蛋
- 放入鸡蛋
- 拿到鸡蛋
- 放入鸡蛋
- 拿到鸡蛋
- 放入鸡蛋
- 拿到鸡蛋
- 放入鸡蛋
- 拿到鸡蛋
- 放入鸡蛋
- 拿到鸡蛋
- 放入鸡蛋
- 拿到鸡蛋
- 放入鸡蛋
- 拿到鸡蛋
程序开始,A线程判断盘子是否为空,放入一个鸡蛋,并且唤醒在阻塞队列的一个线程,阻塞队列为空;假设CPU又调度了一个A线程,盘子非空,执行等待,这个A线程进入阻塞队列;然后一个B线程执行,盘子非空,取走鸡蛋,并唤醒阻塞队列的A线程,A线程进入就绪队列,此时就绪队列就一个A线程,马上执行,放入鸡蛋;如果再来A线程重复第一步,在来B线程重复第二步,整个过程就是生产者(A线程)生产鸡蛋,消费者(B线程)消费鸡蛋。