Java阻塞队列 - LinkedBlockingQueue

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);
        //将当前队列元素个数赋给临时变量c并进行+1操作
        c = count.getAndIncrement();
        //如果c+1小于队列容量,表示队列未满,仍可添加元素,则唤醒添加元素线程
        if (c + 1 < capacity)
            notFull.signal();
    } finally {
    	//入队操作后解入队锁,其他线程可以获取入队锁
        putLock.unlock();
    }
    //以上代码中c = count.getAndIncrement();如果在进行该入队操作之前队列元素个数count为0,则c=0,因为count.getAndIncrement()返回+1之前的旧值,此时说明队列由空队列变为了非空队列,此时将唤醒取元素线程
    if (c == 0)
        signalNotEmpty();
}
  • 取出元素

取出元素也有3种方式

public E take() throws InterruptedException {
	//声明临时变量x存储队列元素值
    E x;
    //什么临时变量c存储队列元素个数
    int c = -1;
    //声明临时变量,将元素当前个数赋值给该变量
    final AtomicInteger count = this.count;
    //声明临时变量,将取加元素锁赋值给该变量
    final ReentrantLock takeLock = this.takeLock;
    //入队操作前上入队锁
    takeLock.lockInterruptibly();
    try {
    	//当队列空时,取出元素线程一直阻塞
        while (count.get() == 0) {
            notEmpty.await();
        }
        //元素出队操作
        x = dequeue();
        //将当前队列元素个数赋给临时变量c并进行-1操作
        c = count.getAndDecrement();
        //如果c>1,表示当前出队操作之后count>0,即队列未空,仍可取元素,则唤醒取出元素线程
        if (c > 1)
            notEmpty.signal();
    } finally {
    	//出队操作后解出队锁,其他线程可以获取出队锁
        takeLock.unlock();
    }
    //以上代码中c = count.getAndDncrement();如果在进行该出队操作之前队列元素个数count为capacity,则c为队列容量最大值,因为count.getAndDncrement()返回-1之前的旧值,此时说明队列由满队列变为了非满队列,此时将唤醒添加元素线程
    if (c == capacity)
        signalNotFull();
    return x;
}

猜你喜欢

转载自blog.csdn.net/qq_39743981/article/details/106661353