3.集--LinkedTransferQueue得知
近期在阅读开源项目里,发现有几个project都不尽同样地使用LinkedTransferQueue这个数据结构。比方netty,grizzly,xmemcache,Bonecp。
Bonecp还扩展出一个BoundTransferQueue。
LinkedTransferQueue最早出如今JSR66R(一个轻量级并行运行框架)包中。眼下已合并到JDK7中。
JSR66的负责人正是大名顶顶的Doug Lea.
尽管LinkedTransferQueue被集成在JDK7中,但眼下主流的JDK平台仍然是JDK6。以致开源项目开发人员都不迫及地把他集成在自已的项目中。
Doug Lea说LinkedTransferQueue是一个聪明的队列。他是ConcurrentLinkedQueue,
SynchronousQueue (in “fair” mode), and unbounded LinkedBlockingQueue的超集。
有一篇论文讨论了其算法与性能:地址:http://www.cs.rice.edu/~wns1/papers/2006-PPoPP-SQ.pdf
LinkedTransferQueue实现了一个重要的接口TransferQueue,该接口含有以下几个重要方法:
1. transfer(E e)
若当前存在一个正在等待获取的消费者线程。即立马移交之;否则,会插入当前元素e到队列尾部,而且等待进入堵塞状态。到有消费者线程取走该元素。
2. tryTransfer(E e)
若当前存在一个正在等待获取的消费者线程(使用take()或者poll()函数)。使用该方法会即刻转移/传输对象元素e;
若不存在,则返回false,而且不进入队列。这是一个不堵塞的操作。
3. tryTransfer(E e, long timeout, TimeUnit unit)
若当前存在一个正在等待获取的消费者线程,会马上传输给它; 否则将插入元素e到队列尾部,而且等待被消费者线程获取消费掉,
若在指定的时间内元素e无法被消费者线程获取。则返回false,同一时候该元素被移除。
4. hasWaitingConsumer()
推断是否存在消费者线程
5. getWaitingConsumerCount()
获取全部等待获取元素的消费线程数量
事实上transfer方法在SynchronousQueue的实现中就已存在了,仅仅是没有做为API暴露出来。SynchronousQueue有一个特性:它本身不存在容量,仅仅能进行线程之间的
元素传送。SynchronousQueue在运行offer操作时。假设没有其它线程运行poll,则直接返回false.线程之间元素传送正是通过transfer方法完毕的。
有一个使用案例。我们知道ThreadPoolExecutor调节线程的原则是:先调整到最小线程,最小线程用完后,他会将优先将任务放入缓存队列(offer(task)),等缓冲队列用完了,才会向最大线程数调节。这似乎与我们所理解的线程池模型有点不同。我们一般採用添加到最大线程后,才会放入缓冲队列中,以达到最大性能。
ThreadPoolExecutor代码段:
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
if (poolSize >= corePoolSize || !addIfUnderCorePoolSize(command)) {
if (runState == RUNNING && workQueue.offer(command)) {
if (runState != RUNNING || poolSize == 0)
ensureQueuedTaskHandled(command);
}
else if (!addIfUnderMaximumPoolSize(command))
reject(command); // is shutdown or saturated
}
}
假设我们採用SynchronousQueue作为ThreadPoolExecuto的缓冲队列时,在没有线程运行poll时(即存在等待线程)。则workQueue.offer(command)返回false,这时ThreadPoolExecutor就会添加线程,最快地达到最大线程数。
但也仅此而已,也由于SynchronousQueue本身不存在容量,也决定了我们一般无法採用SynchronousQueue作为ThreadPoolExecutor的缓存队列。而一般採用LinkedBlockingQueue的offer方法来实现。
最新的LinkedTransferQueue或许能够帮我们解决问题,后面再说。
transfer算法比較复杂,实现非常难看明确。大致的理解是採用所谓双重数据结构(dual data structures)。之所以叫双重,其原因是方法都是通过两个步骤完毕:
保留与完毕。比方消费者线程从一个队列中取元素,发现队列为空。他就生成一个空元素放入队列,所谓空元素就是数据项字段为空。
然后消费者线程在这个字段上旅转等待。这叫保留。直到一个生产者线程意欲向队例中放入一个元素,这里他发现最前面的元素的数据项字段为NULL,他就直接把自已数据填充到这个元素中。即完毕了元素的传送。大体是这个意思。这样的方式优美了完毕了线程之间的高效协作。
对于LinkedTransferQueue,Doug Lea进行了尽乎极致的优化。Grizzly的採用了PaddedAtomicReference:
public LinkedTransferQueue() {
QNode dummy = new QNode(null, false);
head = new PaddedAtomicReference<QNode>(dummy);
tail = new PaddedAtomicReference<QNode>(dummy);
cleanMe = new PaddedAtomicReference<QNode>(null);
}
static final class PaddedAtomicReference<T> extends AtomicReference<T> { // enough padding for 64bytes with 4byte refs
Object p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb, pc, pd, pe;
PaddedAtomicReference(T r) { super(r); }
}
PaddedAtomicReference相对于父类AtomicReference仅仅做了一件事情,就将共享变量追加到64字节。我们能够来计算下。一个对象的引用占4个字节,
它追加了15个变量共占60个字节,再加上父类的Value变量,一共64个字节。这么做的原因。
请參考http://www.infoq.com/cn/articles/ftf-java-volatile
http://rdc.taobao.com/team/jm/archives/1719 这两文章。做JAVA。假设想成为Doug Lea这种大师,也要懂体系结构(待续)
原文地址:http://guojuanjun.blog.51cto.com/277646/948298/
版权声明:本文博主原创文章。博客,未经同意不得转载。
3.集--LinkedTransferQueue得知的更多相关文章
- Redis单点到集群迁移
目录 一.简介 一.简介 1.环境 源 192.168.1.185的6379 目标 192.168.1.91的7001,7002 192.168.1.92的7003,7004 192.168.1.94 ...
- js 正则之 判断密码类型
原文:js 正则之 判断密码类型 今天没啥写的,就分享个思路吧.之前在群里讨论的时候,谢亮兄弟说判断密码是否是纯数字,纯字母之类的.如果用 , 条判断,那就老长一大段了.这个思路是我之前看 jQuer ...
- ResultSet.TYPE_SCROLL_SENSITIVE问题(完全摘自他人)
摘自CSDN博客 我们先来做一个例子,在例子中我用的是mysql-essential-5.1.30-win32版. 来跟我做以下几个命令: mysql> create database axma ...
- ResultSet.TYPE_SCROLL_SENSITIVE到底发生了什么?
转自:https://blog.csdn.net/axman/article/details/3984103 这个问题我在几年前说过,但今天再次从CSDN上看到有人问这个问题,可以看出,真正懂这个问题 ...
- Redis集群搭建1
wget .168.0.201:6379 192.168.0.201:6380 192.168.0.201:6381 192.168.0.202:16379 192.168.0.202:16380 1 ...
- hadoop 集群的配置
在经过几天折腾,终于将hadoop环境搭建成功,整个过程中遇到各种坑,反复了很多遍,光虚拟机就重新安装了4.5次,接下来就把搭建的过程详细叙述一下 0.相关工具: 1,系统环境说明: 我这边给出我的集 ...
- Memcached集群/分布式/高可用 及 Magent缓存代理搭建过程 详解
当网站访问量达到一定时,如何做Memcached集群,又如何高可用,是接下来要讨论的问题. 有这么一段文字来描述“Memcached集群” Memcached如何处理容错的? 不处理!:) 在memc ...
- zookeeper在集群负载均衡中的应用
zookeeper本身是不提供负载均衡的策略,需要自己来实现,所以这里确切的说,是在负载均衡中应用到了zookeeper做集群的协调. 对于HTTP请求的负载均衡,成熟的解决方案是Nginx(或Hap ...
- Linux下Hadoop2.6.0集群环境的搭建
本文旨在提供最基本的,可以用于在生产环境进行Hadoop.HDFS分布式环境的搭建,对自己是个总结和整理,也能方便新人学习使用. 基础环境 JDK的安装与配置 现在直接到Oracle官网(http:/ ...
随机推荐
- uva10341 - solve it (二分查找)
题目:uva10341-solve it 题目大意:求解给定的方程式解题思路:由于这个方程式在给定的x的范围内是单调递减的.所以能够用二分查找来尝试x的值.这里的 x是要求保留4小数,所以当区间缩小到 ...
- Codeforces Round #256 (Div. 2) D. Multiplication Table 二分法
D. Multiplication Table time limit per test 1 second memory limit per test 256 megabytes input st ...
- Myeclipse 10/2014 配置插件(svn、maven、properties、velocity)方法
一.构造SVN具体说明 什么是SVN? 管理软件开发过程中的版本控制工具. 以下会以两种方式来介绍怎么安装svn,myeclipse安装SVN插件步骤.以myeclipse 2014为例,第一种是最常 ...
- 新建WindowsPhone项目时提示未将对象引用设置到对象的实例
问题: 安装好新系统之后(只有Windows8 专业版和企业版支持hyper-v),然后安装vs2012,再安装Wp8 Sdk,安装完毕后新建Windows Phone项目,会提示未将对象引用设置到对 ...
- AE 先进的视频画面 快速释放 慢动作
视频画面细腻,或快速释放.慢速播放视频.其实很easy.在使用图层time中间Enable Time remapping能够.快捷键ctrl+alt+T债券,我无法使用,我没有深究. 在这一点上,在视 ...
- SQLServer 2012异常问题(一)--故障转移群集+镜像环境导致作业执行失败
原文:SQLServer 2012异常问题(一)--故障转移群集+镜像环境导致作业执行失败 先感谢一下我的同事们最先发现此问题,鸣谢:向飞.志刚.海云 最近在生产环境发现一个诡异的问题: 环境:WIN ...
- NSIS:使用PassDialog插件实现密码安装(卸载)功能
原文 NSIS:使用PassDialog插件实现密码安装(卸载)功能 有时,出于特殊的需求,我们要给安装或卸载程序加一个密码,只有输入了正确的密码才可以继续.比如: 下面我们使用插件来实现安装密码: ...
- SQLServer表变量对IO及内存影响测试
原文:SQLServer表变量对IO及内存影响测试 1. 测试创建表变量对IO的影响 测试创建表变量前后,tempdb的空间大小,目前使用sp_spaceused得到大小,也可以使用视图sys.dm_ ...
- php:的图形计算器的面向对象的版本武器2
通过自带部分result.class.php分流,由于这三个类继承shape这个类,让我们来看看,面向对象的继承. shape.class.shape档 <?php abstract class ...
- 在SurfaceView中自由书写和擦除
/////////继承SurfaceView 的类 public class PaintView extends SurfaceView implements Runnable,SurfaceHold ...