LinkedBlockingQueue源码浅析

说明

LinkedBlockingQueue是基于链表实现的,所以说它不同于ArrayBlockingQueue,它
的容量限制被写死在代码了,即int的最大值,至于其使用类似于ArrayBlockingQueue

原理说明

成员属性

在这里插入图片描述

从属性上看,这是个双锁控制的同步队列,不同于ArrayBlockingQueue,ArrayBlockingQueue是一把锁双条件控制,这里不难想象,它加锁的方式应该是估计应该 是 每添加一个节点,就直接take,put锁全加上,确保take和put不会同时在删除一个节点,又同时在该删除节点后面新增节点,实际上并非如此

put方法

public void put(E e) throws InterruptedException {
        阻塞队列一般都会有的非空异常判断
        if (e == null) throw new NullPointerException();
        int c = -1;
        新增一个节点
        Node<E> node = new Node<E>(e);
        获取put锁
        final ReentrantLock putLock = this.putLock;
        获取当前容纳元素的数量
        final AtomicInteger count = this.count;
        put上锁
        putLock.lockInterruptibly();
        try {
            检查队列是否已经是最大容量了
            while (count.get() == capacity) {
                容量达到最大put条件阻塞
                notFull.await();
            }
            添加一个节点到队列中
            enqueue(node);
            重新计算当前容纳的元素个数
            c = count.getAndIncrement();
            if (c + 1 < capacity)
                获取put方法放元素
                notFull.signal();
        } finally {
            释放put锁
            putLock.unlock();
        }
        判断是否有元素在集合中
        if (c == 0)
            唤醒take方法消费元素
            signalNotEmpty();
    }

从上面代码看,并不是直接上双锁来确保take与put方法的调用,再看节点添加方法

    节点赋值,这个方法一般来说是绝对不是线程安全的,纵使添加了和put相关的锁
    对于take来说,这里的操作是有可能被take介入的,倘若take介入,是否会存在问题
    譬如如下问题: last.next = node 刚刚赋值结束,take方法需要获取last节点,由于
    next节点还没来的即装换为last节点,导致take方法获取的不是最新的last节点,继而导致
    丢失了新增的这个node节点,这种情况必然是存在的,那这就说明LinkedBlockingQueue
    是存在并发隐患的吗?事实是如此吗,见下图分析
    private void enqueue(Node<E> node) {
        last = last.next = node;
    }

头节点:发生上述情况,而此时last是null,不存在上述描述的问题
在这里插入图片描述
中间节点:操作的位置都不一样了,不存在竞争节点的问题
在这里插入图片描述
原来是我想多了,再者这个容器压根就不可能同时存在2个take方法在执行,也不可能
存在2个put方法在执行,线程的临界点只会是最多存在一个take一个put方法

不过看看remove方法就,这不就是直接上双锁吗,哈哈,只能说这LinkedBlockingQueue的锁上的很有料啊

    public boolean remove(Object o) {
        if (o == null) return false;
        /**
	      void fullyLock() {
	        putLock.lock();
	        takeLock.lock();
	      }
        */
        fullyLock();
        try {
            for (Node<E> trail = head, p = trail.next;
                 p != null;
                 trail = p, p = p.next) {
                if (o.equals(p.item)) {
                    unlink(p, trail);
                    return true;
                }
            }
            return false;
        } finally {
            fullyUnlock();
        }
    }

总结:1) LinkedBlockingQueue是一个容量特别大(int 最大值)的容器
2) 这吗大的容量通常来说对于put方法几乎都是排队执行的没什么阻塞

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值