LinkedBlockingQueue源码深入解析

常用方法

在这里插入图片描述

类注释

  • 基于链表的阻塞队列
  • FIFO特性
  • 链表默认为Integer的最大值

数据结构

    /**
     * 链表
     */
    static class Node<E> {
        E item;

        /**
         * 为null时,表示当前节点是队尾
         */
        Node<E> next;

        Node(E x) { item = x; }
    }

    /** 未指定的话,容量为Integer最大值 */
    private final int capacity;

    /** 当前元素数量 */
    private final AtomicInteger count = new AtomicInteger();

    /**
     * 头节点
     */
    transient Node<E> head;

    /**
     * 尾结点
     */
    private transient Node<E> last;

    /** take, poll 持有的锁*/
    private final ReentrantLock takeLock = new ReentrantLock();

    /** Wait queue for waiting takes */
    private final Condition notEmpty = takeLock.newCondition();

    /** put, offer 持有的锁 */
    private final ReentrantLock putLock = new ReentrantLock();

    /** Wait queue for waiting puts */
    private final Condition notFull = putLock.newCondition();

锁分为take锁和put锁,是为了两个操作可以同时进行,互不影响

操作方法

初始化操作
  • 由于是链表结构,理论上可以是无限大,所以容量大小不会和数组那样需要提前申请空间而影响性能。初始容量太小会导致队列很快放满
PUT 方法
// 添加元素e到队列尾部
// 新增元素,空间满等待,空间不满直接成功
public void put(E e) throws InterruptedException {
        if (e == null) throw new NullPointerException();
        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 = count.getAndIncrement();
            //还有容量,通知其他线程
            if (c + 1 < capacity)
                notFull.signal();
        } finally {
            putLock.unlock();
        }
        //队列中里有一个元素,唤醒一个take等待线程
        if (c == 0)
            signalNotEmpty();
}
//入队,把元素直接放在队尾
private void enqueue(Node<E> node) {
        // assert putLock.isHeldByCurrentThread();
        // assert last.next == null;
        last = last.next = node;
}

take方法
public E take() throws InterruptedException {
        E x;
        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
            c = count.getAndDecrement();
            if (c > 1)
                notEmpty.signal();
        } finally {
            takeLock.unlock();
        }
        if (c == capacity)
            signalNotFull();
        return x;
}
private E dequeue() {
        // assert takeLock.isHeldByCurrentThread();
        // assert head.item == null;
        Node<E> h = head;
        Node<E> first = h.next;
        h.next = h; // help GC
        head = first;
        E x = first.item;
        first.item = null;
        return x;
}

这个工具类可以用到各种阻塞场景中

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值