ArrayBlockingQueue-我们到底能走多远系列(42)
我们到底能走多远系列(42)
扯淡:
乘着有空,读些juc的源码学习下。后续把juc大致走一边,反正以后肯定要再来。
主题:
java.util.Queue
that additionally supports operations that wait for the queue to become non-empty when retrieving an element, and wait for space to become available in the queue when storing an element. Throws exception | Special value | Blocks | Times out | |
Insert | add(e) |
offer(e) |
put(e) |
offer(e, time, unit) |
Remove | remove() |
poll() |
take() |
poll(time, unit) |
Examine | element() |
peek() |
not applicable | not applicable |
- // 队列存放元素的容器
- final Object[] items;
- // 下一次读取或移除的位置
- int takeIndex;
- // 存放下一个放入元素的位置
- int putIndex;
- // 队列里有效元素的数量
- int count;
- // 所有访问的保护锁
- final ReentrantLock lock;
- // 等待获取的条件
- private final Condition notEmpty;
- // 等待放入的条件
- private final Condition notFull;
2,整个队列是有一个环绕机制的,比如这时候我一直取数据,那么读取的下标会一直后移,知道数组的末尾。如果这时候制定数组的尾部后一个下标时数组的头位。如此即实现环绕的一个队列。如此实现十分精妙,可说是整个队列实现的基础机制。
如此,这个队列的容量是不可改变的。
- // 指针前移
- final int inc(int i) {
- return (++i == items.length) ? 0 : i;
- }
- // 指针后移
- final int dec(int i) {
- return ((i == 0) ? items.length : i) - 1;
- }
3,直接看下核心的put和take方法实现:
put
- public void put(E e) throws InterruptedException {
- checkNotNull(e);//不能放null
- final ReentrantLock lock = this.lock;//先把锁赋给final修饰的局部变量
- // 在JUC的很多类里,都会看到这种写法:把类的属性赋值给方法内的用final修饰一个变量。
- // 这是因为类的属性是存放在堆里的,方法内的变量是存放在方法栈上的,访问方法栈比访问堆要快。
- // 在这里,this.lock属性要访问两次,通过赋值给方法的局部变量,就节省了一次堆的访问。
- // 其他的类属性只访问一次就不需要这样处理了。
- lock.lockInterruptibly();//加锁
- try {
- //循环保证避免避免虚假唤醒,虚假唤醒就是此事如果有多个线程都wait,
//而被同时唤醒时都会去执行下面的insert- //如果在while循环中,那么唤醒后先判断count大小,来确定是继续wait还是insert。
- while (count == items.length)
- notFull.await();//阻塞线程
- insert(e);
- } finally {
- lock.unlock();//释放锁
- }
- }
take
- public E take() throws InterruptedException {
- final ReentrantLock lock = this.lock;
- lock.lockInterruptibly();
- try {
- while (count == 0)
- notEmpty.await();
- return extract();
- } finally {
- lock.unlock();
- }
- }
其中使用到insert和extract方法,当然也可以看到只有持有锁的情况下才会调用这两个方法,如此这个方法的调用不需要关系是否线程安全,调用前保证线程安全:
- private void insert(E x) {
- items[putIndex] = x;// 1,存值,非常简便
- putIndex = inc(putIndex);//2,移动下标,使用inc方法
- ++count;//3,增加元素总数
- notEmpty.signal();//4,通知在非空条件上等待的读线程
- }
- private E extract() {
- final Object[] items = this.items;//先将类变量赋给方法变量,前面提过这个用处
- E x = this.<E>cast(items[takeIndex]);
- items[takeIndex] = null;
- takeIndex = inc(takeIndex);
- --count;
- notFull.signal();
- return x;
- }
操作示意图:
1,一个环的数组
2,再放一个元素:
3,取一个元素
当然ArrayBlockingQueue里还有其他方法,这里就不赘述了。有兴趣的同学可以深入继续探索。
总结:
1,一个环的数组设计十分巧妙。
2,将类变量赋给方法变量的编码方式
---------------------------------------20161202补充---------------------------------------------
ArrayBlockingQueue利用下面三个元素控制队列:
- /** Main lock guarding all access */
- final ReentrantLock lock;
- /** Condition for waiting takes */
- private final Condition notEmpty;
- /** Condition for waiting puts */
- private final Condition notFull;
ReentrantLock:可重入锁,在操作队列时,用来同步化。
- public ArrayBlockingQueue(int capacity, boolean fair) {
- if (capacity <= 0)
- throw new IllegalArgumentException();
- this.items = new Object[capacity];
- lock = new ReentrantLock(fair);
- notEmpty = lock.newCondition();
- notFull = lock.newCondition();
- }
比如下面的take方法,就是用Condition来实现blocking的。
- public E take() throws InterruptedException {
- final ReentrantLock lock = this.lock;
- lock.lockInterruptibly();
- try {
- while (count == 0)
- notEmpty.await();
- return dequeue();
- } finally {
- lock.unlock();
- }
- }
而当有元素放入BlockingQueue时,用notEmpty.signal()方法通知阻塞在这个条件上的线程可以抢机会进入执行了
- private void enqueue(E x) {
- // assert lock.getHoldCount() == 1;
- // assert items[putIndex] == null;
- final Object[] items = this.items;
- items[putIndex] = x;
- if (++putIndex == items.length)
- putIndex = 0;
- count++;
- notEmpty.signal();
- }
以上的同步实现方式应该是很经典的实现方式。
让我们继续前行
----------------------------------------------------------------------
努力不一定成功,但不努力肯定不会成功。
ArrayBlockingQueue-我们到底能走多远系列(42)的更多相关文章
- ThreadPoolExecutor机制探索-我们到底能走多远系列(41)
我们到底能走多远系列(41) 扯淡: 这一年过的不匆忙,也颇多感受,成长的路上难免弯路,这个世界上没人关心你有没有变强,只有自己时刻提醒自己,不要忘记最初出发的原因. 其实这个世界上比我们聪明的人无数 ...
- JMS生产者+单线程发送-我们到底能走多远系列(29)
我们到底能走多远系列(29) 扯淡: “然后我俩各自一端/望着大河弯弯/终于敢放胆/嘻皮笑脸/面对/人生的难” --- <山丘> “迎着风/迎向远方的天空/路上也有艰难/也有那解 ...
- Spring mvc源码url路由-我们到底能走多远系列(38)
我们到底能走多远系列38 扯淡: 马航的事,挺震惊的.还是多多珍惜身边的人吧. 主题: Spring mvc 作为表现层的框架,整个流程是比较好理解的,毕竟我们做web开发的,最早也经常接触的就是一个 ...
- 服务调用方案(Spring Http Invoker) - 我们到底能走多远系列(40)
我们到底能走多远系列(40) 扯淡: 判断是否加可以效力于这家公司,一个很好的判断是,接触下这公司工作几年的员工,了解下生活工作状态,这就是你几年后的状态,如果满意就可以考虑加入了. 主题: 场景: ...
- node实现http上传文件进度条 -我们到底能走多远系列(37)
我们到底能走多远系列(37) 扯淡: 又到了一年一度的跳槽季,相信你一定准备好了,每每跳槽,总有好多的路让你选,我们的未来也正是这一个个选择机会组合起来的结果,所以尽可能的找出自己想要的是什么再做决定 ...
- node模拟http服务器session机制-我们到底能走多远系列(36)
我们到底能走多远系列(36) 扯淡: 年关将至,总是会在一些时间节点上才感觉时光飞逝,在平时浑浑噩噩的岁月里都浪费掉了太多的宝贵.请珍惜! 主题: 我们在编写http请求处理和响应的代码的时 ...
- js中this和回调方法循环-我们到底能走多远系列(35)
我们到底能走多远系列(35) 扯淡: 13年最后一个月了,你们在13年初的计划实现了吗?还来得及吗? 请加油~ 主题: 最近一直在写js,遇到了几个问题,可能初入门的时候都会遇到吧,总结下. 例子: ...
- html5实现饼图和线图-我们到底能走多远系列(34)
我们到底能走多远系列(34) 扯淡: 送给各位一段话: 人生是一个不断做加法的过程 从赤条条无牵无挂的来 到学会荣辱羞耻 礼仪规范 再到赚取世间的名声 财富 地位 ...
- Bean实例化(Spring源码阅读)-我们到底能走多远系列(33)
我们到底能走多远系列(33) 扯淡: 各位: 命运就算颠沛流离 命运就算曲折离奇 命运就算恐吓着你做人没趣味 别流泪 心酸 更不应舍弃 ... 主题: Spring源码阅读还在继 ...
随机推荐
- 什么是 Help Desk?
科技如何帮助公司发展,关键就在于保证IT系统的安全稳定运行.我们都知道要保证系统100%可用非常难实现,那么如何在系统故障时减少处置时间?一个有效的办法就是帮助台(Help Desk).那么什么是帮助 ...
- Key Figure、Exception Aggreagion、Non-Cumulative KeyFigure
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...
- Json不知道key值情况下获取第一个键值对
JObject jsonData = new JObject(); jsonData.Add("1", "1"); jsonData.Add("2&q ...
- window svn链接
我学会怎么建立window SVN服务器了 今天,终于学会怎么自己搭建SVN服务了,以前一直用的都是公司的SVN服务,没接触过,觉得很神秘,曾经我一个同事弄了好几天,也没搭成,对我打击挺大的:( 觉得 ...
- == 区别 equals
==操作符专门用来比较值是否相等 int a=10; int b=10; 则 a==b, 返回 true. 但是, String a = new String("foo"); St ...
- Java安装与环境配置
Java安装 第一步 安装jdk-8u111-windows(根据操作系统的位数选择安装32位或64位) 注:路径用英文,不要出现中文和空格等.jdk和jre放在同一个文件夹下,便于管理 本例的路径为 ...
- 你真的会写单例模式吗-------Java实现
转载: 你真的会写单例模式吗--Java实现 单例模式可能是代码最少的模式了,但是少不一定意味着简单,想要用好.用对单例模式,还真得费一番脑筋.本文对Java中常见的单例模式写法做了一个总结,如有错漏 ...
- webwork
代码结构,html页面引入两个js文件,work.js和main.js work.js (function () { onmessage = function (e) { var num = e.da ...
- Linux运行级详解
对于那些在DOS/Win9x/NT平台下的高级用户而言,Linux似乎是一个怪物.没有config.sys,没有 autoexec.bat,具有个人特色的机器配置不知道从何开始. 需要说明的是,很多人 ...
- Windows下pip安装包报错:Microsoft Visual C++ 9.0 is required Unable to find vcvarsall.bat
刚在机器上windows环境下装上pip方便以后安装包的时候使用,谁知道第一次使用pip安装asyncio的时候就报错. 在Windows7x64下使用pip安装包的时候提示报错:Microsoft ...