LinkedBlockingQueue源码解析


put 和 take方法 其实 思想就是反的 举一反三即可
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();// 加入等待队列 等待 被唤醒 
        }
        // 我个人认为 精髓在这2个代码.

		// 首先  put  和 take 采用了 2把锁 互不相干  但是 这个 地方 竟然允许 同时有可能有2个
		// 线程同时操作 items 单向链表  我开始也觉得 不可思议 但是大师就是 大师

		//  如果是put 那么 永远操作 last节点 也就是说 如果 在put 线程操作 last的时候也就是 能被take的
		// 最后一个节点。就算2个线程同时在操作 但是 put线程永远操作 last节点 把 追加的item 添加到last.next
		// 之中。因为由于在操作 未cas之前 就算put了 但是没有cas take线程也无法消费 这个item
		// 只会把最后 一个 last 设置为 head  因为每次取出 item 都会把取出 的节点设置为 head 所以
		// 即使这段代码 没有 加 take 和put 关联的锁 也能保证线程安全性 就是靠这点
		// 因为 在put 之后没有cas 只是提前put进去 你消费不了

		// 只要保证 添加多少个 item 就是添加多少个  消费多少个item就是消费多少个 不会出现数据不一致性
		// 所以也不需要加锁了
        enqueue(node);
        // 这个地方 之所以一个 atomicInteger 就行 是因为 只要 items总数加加 不会出现 多线程的 原子 可见性即可
        
        // 而take 的线程只要保证 我take了一个 总数必须减去一是原子,可见性 即可 
        c = count.getAndIncrement(); // ++ 返回 ++之前的值
        
        if (c + 1 < capacity)
         // 这个地方避免了 put满后 大量线程 在等待队列上 但是 后续任务的吞吐量远远不足导致 线程一直处于等待
         //队列上的情况  ,因为put满后 take 只会当 C= 临界值 来signalNotFull 一次 后面吞吐量
       	// 跟不上 就可能出现 一直被挂着 

		//为什么我这么断定 是因为 为什么会item在明明小于 最大item数 竟然去唤醒 等待队列中的线程 
		// 我item都没塞满 为什么可能 出现线程在 等待队列上呢? 就是由于上面这点
            notFull.signal();
    } finally {
        putLock.unlock();
    }
    // 如果=0 代表之前有可能会有很多线程 在takeCondition上等待 唤醒
    // 为什么是C=0 才需要 唤醒 take的等待队列呢 因为 如果是 c=界限值 才唤醒 那么
    // 任务是满的 还有线程在 take等待队列上 等待 这些等待 不就是 之前没有 任务拿 而阻塞来的吗。
    if (c == 0)
        signalNotEmpty();
}

enqueue(node);
c = count.getAndIncrement();
不管是在 poll 还是在put
都是先放 后++ 或者 先取后 - -

其实这也是 有考虑得 因为如果 是poll得情况
先减 后放 会出现 其实减了 但是没poll拿出来这个时候 如果 有线程拿到
pollLock 去放 岂不是 会真实得链表长度已经 超过界限 但是 实际显示没超

put 如果是先++ 在put 会出现 我还没放 但是 你增加了技术 去poll得线程觉得有
返回得其实是null 但是 put得线程其实还没放进去,所以 把去拿 去取 放在 cas
之前 从而规避了这些问题

大师的思想 直得 深思,可怕的是 十几年前就这么 厉害了 我就像个弟弟

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值