此文已由作者赵计刚授权网易云社区发布。
欢迎访问网易云社区,了解更多网易技术产品运营经验。
4.3、public E take() throws InterruptedException
原理:
使用方法:
try { abq.take(); } catch (InterruptedException e) { e.printStackTrace(); }
源代码:
/** * 出队: * 如果队列空了,一直阻塞,直到队列不为空或者线程被中断 */ 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(即被其他线程唤醒) * (唤醒其实就是,有线程将一个元素入队了,然后调用notEmpty.signal()唤醒其他等待这个条件的线程,同时队列也不空了) */ notEmpty.await(); } x = dequeue();//出队 c = count.getAndDecrement();//元素数量-1 if (c > 1) notEmpty.signal(); } finally { takeLock.unlock(); } if (c == capacity) signalNotFull(); return x; }
总结:
1、具体入队与出队的原理图:
图中每一个节点前半部分表示封装的数据x,后边的表示指向的下一个引用。
1.1、初始化
初始化之后,初始化一个数据为null,且head和last节点都是这个节点。
1.2、入队两个元素过后
这个可以根据入队方法enqueue(E x)来看,源代码再贴一遍:
其实这我们就可以发现其实真正意义上出队的头节点是Head节点的下一个节点。(这也就是Node这个内部类中对next的注释,我没有翻译)
1.3、出队一个元素后
表面上看,只是将头节点的next指针指向了要删除的x1.next,事实上这样我觉的就完全可以,但是jdk实际上是将原来的head节点删除了,而上边看到的这个head节点,正是刚刚出队的x1节点,只是其值被置空了。
这一块对应着源代码来看:dequeue()
2、三种入队对比:
3、三种出队对比:
4、ArrayBlockingQueue与LinkedBlockingQueue对比
两个疑问:
这两个疑问,都是基于对于AtomicInteger的不熟,不明白LinkedBlockingQueue引用的这两个方法(getAndIncrement和getAndDecrement)先返回旧值还是新值,关于AtomicInteger的源码介绍,请查看《第十一章 AtomicInteger源码解析》,具体链接如下:
http://www.cnblogs.com/java-zhao/p/5140158.html
免费领取验证码、内容安全、短信发送、直播点播体验包及云服务器等套餐
更多网易技术、产品、运营经验分享请点击。