按关键词阅读:
null 值在这里通常用于作为特殊值返回 , 比如 poll() 返回 null , 则代表 poll 失败 。
所以 , 如果允许插入 null 值的话 , 那获取的时候 , 就不能很好地用 null 来判断到底是代表失败 , 还是获取的值就是 null 值 。
enqueue 入队/** * Links node at end of queue. * * @param node the node */private void enqueue(Node
这个方法写的非常的精炼 。
建议看不懂的同学可以分成 2 步来看:
last.next = node;last = last.next;
将 node 节点放在队列的最后 , 将 last.next 变为新的队尾 。
put 放入元素我们来重点看一下 put() 方法 。
/** * Inserts the specified element at the tail of this queue, waiting if * necessary for space to become available. * * @throws InterruptedException {@inheritDoc} * @throws NullPointerException {@inheritDoc} * @author 老马啸西风 */public void put(E e) throws InterruptedException {if (e == null) throw new NullPointerException();// Note: convention in all put/take/etc is to preset local var// holding count negative to indicate failure unless set.int c = -1;// 创建节点Node
signalNotEmpty这个方法是通知 notEmpty , 便于元素可以取出 。
/** * Signals a waiting take. Called only from put/offer (which do not * otherwise ordinarily lock takeLock.) */private void signalNotEmpty() {final ReentrantLock takeLock = this.takeLock;takeLock.lock();try {notEmpty.signal();} finally {takeLock.unlock();}}
当然这里的对于 notEmpty 的唤醒 , 是通过 takeLock 保证并发安全的 。
这样看来 , LinkedBlockingQuue 和 ArrayBlockingQueue 实现上还是有很大差异的 。
take 获取元素获取元素的实现如下:
/**** 获取一个元素** @author 老马啸西风*/public E take() throws InterruptedException {E x;// 默认的 c = -1;int c = -1;// 并发控制 。// 注意 , 这里的读写锁是分离的 。 这个和 ArrayBlockingList 是不同的 。final AtomicInteger count = this.count;final ReentrantLock takeLock = this.takeLock;takeLock.lockInterruptibly();try {// 如果元素为空 , 则陷入等待 。while (count.get() == 0) {notEmpty.await();}// 执行出队x = dequeue();c = count.getAndDecrement();// 如果总数 > 1 , 则说明不再为空 。// 唤醒 notEmpty 等待的线程if (c > 1)notEmpty.signal();} finally {takeLock.unlock();}// 如果总数等于容量 , 唤醒 notFull// 感觉这个唤醒微妙 , 因为 capacity 默认是 Integer#MAX_VALUE 最大值if (c == capacity)signalNotFull();return x;}
dequeue 出队方法/** * Removes a node from head of queue. * 从队首移除元素 * * @author 老马啸西风 * @return the node */private E dequeue() {// assert takeLock.isHeldByCurrentThread();// assert head.item == null;Node
signalNotFull 唤醒 notFull/** * Signals a waiting put. Called only from take/poll. * 唤醒所有等待放入的线程 。*/private void signalNotFull() {final ReentrantLock putLock = this.putLock;putLock.lock();try {notFull.signal();} finally {putLock.unlock();}}
小结本文从 LinkedBlockingQueue 的入门使用 , 逐渐深入到源码分析 。
实际上原理都是类似的 , 不过这个对比 ArrayBlockingQueeu 的锁粒度更加细致 。
没读源码之前 , 我一直以为二者只是链表和数组的区别 。
很多事情 , 都不是我们以为的那个样子 。
希望本文对你有帮助 , 如果有其他想法的话 , 也可以评论区和大家分享哦 。
【阻塞队列(3)LinkedBlockingQueue源码详解】各位极客的点赞收藏转发 , 是老马持续写作的最大动力!
文章插图
稿源:(未知)
【傻大方】网址:http://www.shadafang.com/c/111J2HT2020.html
标题:阻塞队列(3)LinkedBlockingQueue源码详解( 三 )