java并发编程条件队列的唤醒机制探究

来源:互联网 发布:中国儿童编程网 编辑:程序博客网 时间:2024/05/22 14:08

这里写图片描述
bf1,bf2是两个大小各为3的条件队列。3将要put进bf1,此时因为bf1已满而已调用wait()方法挂起线程,此时若对bf2()执行take()方法并调用notifyall()是否会唤醒wait()中的bf1?(对两个队列的操作存在于两个不同的线程中)

先上代码

public abstract class BaseBoundedBuffer<V>{    private final V[] buf;    private  int tail;    private  int head;    private  int count;    protected BaseBoundedBuffer(int capacity) {        this.buf = (V[]) new Object[capacity];    }    protected synchronized final void doPut(V v){        buf[tail]=v;        if (++tail==buf.length){            tail=0;        }        ++count;    }    protected synchronized final V doTake(){        V v=buf[head];        buf[head]=null;        if (++head == buf.length){            head=0;        }        --count;        return v;    }    public synchronized final boolean isFull(){        return  count==buf.length;    }    public synchronized final boolean isEmpty(){        return count==0;    }}
public class BoundedBuffer<V> extends BaseBoundedBuffer {        private int id;    protected BoundedBuffer(int capacity,int id) {        super(capacity);        this.id=id;    }    public synchronized void put(V v)throws InterruptedException{   //对条件队列执行增加元素的操作        while (isFull()){            System.out.println(id+"快睡了------put");            wait();            System.out.println(id+"醒了--------put");        }        doPut(v);        System.out.println(id+"put"+v);        notifyAll();    }    public synchronized V take() throws InterruptedException{    //对条件队列执行读取操作        while (isEmpty()){            System.out.println(id+"快睡了--------take");            wait();            System.out.println(id+"醒了----------take");        }        V v= (V) doTake();        notifyAll();        return v;    }}
public class BufferTest {    public static void main(String[] args) throws InterruptedException {        BoundedBuffer bf =new BoundedBuffer(3,1);        BoundedBuffer bf2=new BoundedBuffer(3,2);        bf2.put(9999999);        new Thread(){            public void run(){                for (int i=0;i<4;i++){                    try {                        bf.put(i);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }        }.start();        new Thread(){            public void run(){                    try {                        System.out.println( bf2.take());                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }        }.start();    }}
执行结果如下2put99999991put01put11put21快睡了------put9999999

在执行结果第五行的时候便是上图所描述的情况(3想要put进bf1,但是因为已经full,bf1进入wait()状态),第六行输出了9999999,也就说明bf2执行了take()操作,同时也执行了notifyAll()方法,然而对bf1没有产生任何影响。
V v= (V) doTake();
notifyAll();
return v;

结果证明: 在使用条件队列时候,notifyAll()只会唤醒同一对象因执行wait()被挂起的线程