使用等待通知模式实现阻塞队列
一、阻塞队列的属性
1、一个存储数据的数组
2、添加元素的索引,相当于队尾
3、取出元素的索引,相当于队头
3、队列中的元素个数
4、一个互斥锁
5、一个监视队列为空的监视器,一个监视队列为满的监视器
//存储数据的数组 private Object[] data; //添加下标和删除下标和数组当前数量 private int addIndex,removeIndex,size; private Lock lock = new ReentrantLock(); //监视数组是否为空 private Condition notEmpty = lock.newCondition(); //监视数组是否为满 private Condition notFull = lock.newCondition();
二、构造方法
为了简单,我只写了一个传入初始容量的构造方法
public BlockArray(int capa){ data = new Object[capa]; }
三、入队方法
在入队时进行加锁,然后判断队列是否满了,如果满了,阻塞当前线程,不然元素入队,因为这是有界队列,所以在添加后判断队列是否已满,如果已满,则将入队索引置0,size加1,唤醒出队的线程。
public void add(T x) throws InterruptedException { lock.lock(); try { while (size == data.length) notFull.await(); data[addIndex++] = x; if (addIndex == data.length) addIndex = 0; size++; notEmpty.signal(); }finally { lock.unlock(); } }
四、出队方法
在出队时进行加锁,然后判断队列是否为空,如果为空,则阻塞线程,不然出队头,判断出队索引是否越界,如果越界,将其置0,队列元素个数减1,唤醒入队线程。返回队头元素值。
public T remove() throws InterruptedException { lock.lock(); try { while (size == 0) notEmpty.await(); Object x = data[removeIndex]; data[removeIndex++] = null; if (removeIndex == data.length) removeIndex = 0; size--; notFull.signal(); return (T)x; }finally { lock.unlock(); } }
这样一个简单的阻塞队列就已经完成了。源代码如下
class BlockArray<T>{ @Override public String toString() { return "BlockArray{" + "data=" + Arrays.toString(data) + '}'; } //存储数据的数组 private Object[] data; //添加下标和删除下标和数组当前数量 private int addIndex,removeIndex,size; private Lock lock = new ReentrantLock(); //监视数组是否为空 private Condition notEmpty = lock.newCondition(); //监视数组是否为满 private Condition notFull = lock.newCondition(); public BlockArray(int capa){ data = new Object[capa]; } public void add(T x) throws InterruptedException { lock.lock(); try { while (size == data.length) notFull.await(); data[addIndex++] = x; if (addIndex == data.length) addIndex = 0; size++; notEmpty.signal(); }finally { lock.unlock(); } } public T remove() throws InterruptedException { lock.lock(); try { while (size == 0) notEmpty.await(); Object x = data[removeIndex]; data[removeIndex++] = null; if (removeIndex == data.length) removeIndex = 0; size--; notFull.signal(); return (T)x; }finally { lock.unlock(); } } }