近期在阅读开源项目里,发现有几个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得知相关推荐

  1. 编译原理——自上而下的语法分析方法(LL分析法)

    自上而下的语法分析方法(LL分析法) 概述: 语法分析的地位:编译程序的核心部分 任务:词法分析出来的单词序列是否是给定文法的句子 理论:上下文无关文法和下推自动机 方式:自上而下的语法分析(推导)和 ...

  2. LR(1) 分析例子

    来自http://jpkc.gdut.edu.cn/comp/cmpl6/6-4-1.htm#top 6.4 LR(1) 分析  本节介绍比SLR(1)功能更强的LR(1)分析法. 例如下列文法G′为 ...

  3. Hadoop集群的基本操作(一:HDFS操作及MapReduce程序练习)

    实验 目的 要求 目的: 理解HDFS在Hadoop体系结构中的角色: 熟练使用HDFS操作常用的Shell命令: 了解Hadoop集群MapReduce程序的简单使用: (上传WordCount的j ...

  4. Redis单例、主从模式、sentinel以及集群的配置方式及优缺点对比

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 作者:爱宝贝丶 my.oschina.net/zhangxufen ...

  5. 并查集(边带权,拓展域)

    整理的算法模板合集: ACM模板 目录 朴素并查集 维护size的并查集 维护到祖宗节点距离的并查集 路径压缩和按秩合并 2.5 边带权 带权并查集求二分图最小环 2.6 扩展域 2.7 集合中单个元 ...

  6. 负载均衡集群介绍、LVS介绍、LVS调度算法、 LVS NAT模式搭建

    负载均衡集群介绍 LVS介绍 lvs的NAT模式介绍 这种模式借助iptables的nat表来实现,用户的请求到分发器后,通过预设的iptables规则,把请求的数据包转发到后端的服务器上去,这些服务 ...

  7. Redis史上最强【集群】入门实践教程

    来自:我没有三颗心脏 一.Redis 集群概述 Redis 主从复制 到 目前 为止,我们所学习的 Redis 都是 单机版 的,这也就意味着一旦我们所依赖的 Redis 服务宕机了,我们的主流程也会 ...

  8. Kafka:ZK+Kafka+Spark Streaming集群环境搭建(九)安装kafka_2.11-1.1.0

    如何搭建配置centos虚拟机请参考<Kafka:ZK+Kafka+Spark Streaming集群环境搭建(一)VMW安装四台CentOS,并实现本机与它们能交互,虚拟机内部实现可以上网.& ...

  9. paxos整合mysql_微信开源PhxSQL:高可用、强一致的MySQL集群(转载)

    作者: 陈俊超(junechen@tencent.com),微信后台高级工程师,主要负责微信后台核心模块的分布式架构设计和开发.早期负责微信附近的人,摇一摇,朋友圈,群聊等基础架构.现专注于PhxSQ ...

最新文章

  1. 让你的数据离CPU更近一些
  2. SQLSERVER存储过程基本语法
  3. Webstorm快捷键整理
  4. 【Android 应用开发】Android 网络编程 API笔记 - java.net 包 权限 地址 套接字 相关类 简介
  5. 3.1_栈_顺序存储结构(数组形式)
  6. 架空输电线路运行规程_架空输电线路杆塔金具的种类
  7. 解决浏览器刷新vuex数据丢失问题
  8. 简单理解 Kafka 的消息可靠性策略
  9. java 高级泛型_Java 泛型高级
  10. java输入框1-100_Java开发笔记(一百三十九)JavaFX的输入框
  11. mysql不是内部或外部命令,也不是可运行的程序或批处理文件
  12. 算法:回溯十 挑选卡片pickup cards
  13. js实现敏感词过滤算法
  14. cad2019菜单栏怎么调出来_AutoCAD2019怎么把工具栏放左右两边 两侧工具栏调出来...
  15. 关于数位板电脑绘画——入门篇
  16. big_6d77fbb7bde4011fdf01df45fef8d0dd9ddcbdd5.jpg
  17. Win10自动修复无法开机【完美解决】
  18. 香港科技大学委任汪扬教授为副校长(大学拓展)
  19. 二十一世纪大学英语读写教程(第三册)学习笔记(原文)——1 - How I Got Smart(我是如何变聪明的)
  20. 跳跳虎辅助免费体验版

热门文章

  1. 程序员面试什么最重要?
  2. 解决SWFUpload在Chrome、Firefox浏览器下session找不到的问题
  3. 如何有效的压缩虚拟磁盘
  4. SQL 2005中pivot and unpivot的用法
  5. 用GCD来处理大量for loop任务
  6. highcharts 动态生成x轴和折线图
  7. 黑马程序员—java基础总结1
  8. POJ 2808 校门外的树
  9. private、protected、public、published 访问限制(或者叫类成员的可见性)
  10. c#去掉html样式,C# 清除HTML格式