Java阻塞队列 - LinkedBlockingQueue
程序员文章站
2024-02-11 12:45:34
...
LinkedBlockingQueue是Java并发包中一种基于链表结构实现的有界阻塞队列,
- 以下是该类的继承结构图:
- 以下是该类的结构:
LinkedBlockingQueue类:
实现了2个接口:BlockingQueue、Serializable
继承了1个抽象类:AbstractQueue
拥有3个内部类:Node、Itr、LBQSpliterator
拥有3个构造方法:LinkedBlockingQueue()、LinkedBlockingQueue(int capacity)、LinkedBlockingQueue(Collection<? extends E> c)
声明了8个变量:private final int capacity; private final AtomicInteger count = new AtomicInteger(); transient Node<E> head; private transient Node<E> last; private final ReentrantLock takeLock = new ReentrantLock(); private final Condition notEmpty = takeLock.newCondition(); private final ReentrantLock putLock = new ReentrantLock(); private final Condition notFull = putLock.newCondition();
实现了28个方法:
- 6个private方法
//设置队列不为空信号,添加元素操作使用 private void signalNotEmpty() //设置队列不满信号,移出元素操作使用 private void signalNotFull() //元素入队操作 private void enqueue(Node<E> node) //元素出队操作 private E dequeue() //将队列中元素写入流文件 private void writeObject(java.io.ObjectOutputStream s) //读流文件元素到队列中 private void readObject(java.io.ObjectInputStream s)
- 3个default方法
//进队与出队全锁 void fullyLock() //进队与出队全解锁 void fullyUnlock() //remove队列某元素时连接删除元素两端的队列 void unlink(Node<E> p, Node<E> trail)
- 19个public方法
//返回队列中元素个数 public int size() //返回队列中剩余空间 public int remainingCapacity() //队列中添加元素,队列满时,阻塞队列,直到队列有空间时唤醒线程 public void put(E e) //队列中添加元素,队列满时,等待timeout的时间,如果仍然是满的则返回false public boolean offer(E e, long timeout, TimeUnit unit) //队列中添加元素,队列满时,返回false public boolean offer(E e) //队列中移出元素,队列空时,阻塞队列,直到队列不为空时唤醒线程 public E take() //队列中移出元素,队列空时,等待timeout的时间,如果仍然是空的则返回null public E poll(long timeout, TimeUnit unit) //队列中移出元素,队列空时,返回null public E poll() //返回首元素 public E peek() //将某元素移出队列 public boolean remove(Object o) //遍历队列查找某元素是否存在 public boolean contains(Object o) //将队列中元素转成对象数组 public Object[] toArray() /将队列中元素转成元素数组 public <T> T[] toArray(T[] a) //将队列中元素按照一定格式打印输出 public String toString() //清空队列 public void clear() //将队列中全部元素移动到集合中 public int drainTo(Collection<? super E> c) //将队列中指定数量的元素移动到集合中 public int drainTo(Collection<? super E> c, int maxElements) //返回迭代队列的迭代器,便于队列的遍历 public Iterator<E> iterator() //返回可分割迭代器,便于多线程执行 public Spliterator<E> spliterator()
以下简单介绍入队、出队方法、添加元素、移出元素方法
队尾入队、队首出队
- 入队方法
private void enqueue(Node<E> node) {
/** 连等式:
* 第一步、将新元素赋值给旧队尾指针
* 第一步、将新元素赋值给新队尾元素
*/
last = last.next = node;
}
- 出队方法
出对方法涉及到队首和首元素两个变量
整个过程是
将首元素指针赋值给队首
将首元素值取出
将首元素值置空
private E dequeue() {
//队首指针赋值给临时变量h
Node<E> h = head;
//首元素指针赋值给临时变量first
Node<E> first = h.next;
//队首指针赋值给首元素(*)
h.next = h;
//首元素赋值给队首
head = first;
//首元素值取出,放到临时变量x
E x = first.item;
//将首元素值置空,此时首元素已变为队首
first.item = null;
return x;
}
- 添加元素
添加元素有3种方式
public void put(E e) throws InterruptedException {
//添加元素为空,抛出空指针异常
if (e == null) throw new NullPointerException();
//声明临时变量c表示当前队列元素个数
int c = -1;
//声明元素,初始化赋元素值
Node<E> node = new Node<E>(e);
//声明临时变量,将添加元素锁赋值给该变量
final ReentrantLock putLock = this.putLock;
//声明临时变量,将元素当前个数赋值给该变量
final AtomicInteger count = this.count;
//入队操作前上入队锁
putLock.lockInterruptibly();
try {
//当队列元素满时,线程一直阻塞
while (count.get() == capacity) {
notFull.await();
}
//元素入队
enqueue(node);
//将当前队列元素个数+1操作并赋给临时变量c
c = count.getAndIncrement();
//如果c+1小于队列容量,表示队列未满,仍可添加元素
if (c + 1 < capacity)
notFull.signal();
} finally {
//入队操作后解入队锁,其他线程可以获取入队锁
putLock.unlock();
}
//如果
if (c == 0)
signalNotEmpty();
}