Java 容器源码分析之ArrayBlockingQueue和LinkedBlockingQueue(1)
- UID
- 1066743
|
Java 容器源码分析之ArrayBlockingQueue和LinkedBlockingQueue(1)
Java中的阻塞队列接口BlockingQueue继承自Queue接口。
BlockingQueue接口提供了3个添加元素方法。
- add:添加元素到队列里,添加成功返回true,由于容量满了添加失败会抛出IllegalStateException异常
- offer:添加元素到队列里,添加成功返回true,添加失败返回false
- put:添加元素到队列里,如果容量满了会阻塞直到容量不满
3个删除方法。
- poll:删除队列头部元素,如果队列为空,返回null。否则返回元素。
- remove:基于对象找到对应的元素,并删除。删除成功返回true,否则返回false
- take:删除队列头部元素,如果队列为空,一直阻塞到队列有元素并删除
常用的阻塞队列具体类有ArrayBlockingQueue、LinkedBlockingQueue、PriorityBlockingQueue、LinkedBlockingDeque等。
本文以ArrayBlockingQueue和LinkedBlockingQueue为例,分析它们的实现原理。
ArrayBlockingQueueArrayBlockingQueue的原理就是使用一个可重入锁和这个锁生成的两个条件对象进行并发控制(classic two-condition algorithm)。
ArrayBlockingQueue是一个带有长度的阻塞队列,初始化的时候必须要指定队列长度,且指定长度之后不允许进行修改。
它带有的属性如下:
// 存储队列元素的数组,是个循环数组final Object[] items;// 拿数据的索引,用于take,poll,peek,remove方法int takeIndex;// 放数据的索引,用于put,offer,add方法int putIndex;// 元素个数int count;// 可重入锁final ReentrantLock lock;// notEmpty条件对象,由lock创建private final Condition notEmpty;// notFull条件对象,由lock创建private final Condition notFull;
数据的添加ArrayBlockingQueue有不同的几个数据添加方法,add、offer、put方法。
add方法:
public boolean add(E e) { if (offer(e)) return true; else throw new IllegalStateException("Queue full");}
add方法内部调用offer方法如下:
public boolean offer(E e) { checkNotNull(e); // 不允许元素为空 final ReentrantLock lock = this.lock; lock.lock(); // 加锁,保证调用offer方法的时候只有1个线程 try { if (count == items.length) // 如果队列已满 return false; // 直接返回false,添加失败 else { insert(e); // 数组没满的话调用insert方法 return true; // 返回true,添加成功 } } finally { lock.unlock(); // 释放锁,让其他线程可以调用offer方法 }}
insert方法如下:
private void insert(E x) { items[putIndex] = x; // 元素添加到数组里 putIndex = inc(putIndex); // 放数据索引+1,当索引满了变成0 ++count; // 元素个数+1 notEmpty.signal(); // 使用条件对象notEmpty通知,比如使用take方法的时候队列里没有数据,被阻塞。这个时候队列insert了一条数据,需要调用signal进行通知} |
|
|
|
|
|