Treiber Stack简单分析
Abstract
Treiber Stack Algorithm是一个可扩展的无锁栈,利用细粒度的并发原语CAS来实现的,Treiber Stack在 R. Kent Treiber在1986年的论文Systems Programming: Coping with Parallelism中首次出现。
基本原理
该算法的基本原理是:只有当您知道要添加的项目是自开始操作以来唯一添加的项目时,才会添加新的项目。 这是通过使用比较和交换完成的。 在添加新项目时使用堆栈,将堆栈的顶部放在新项目之后。 然后,将这个新构造的头元素(旧头)的第二个项目与当前项目进行比较。 如果两者匹配,那么你可以将旧头换成新头,否则就意味着另一个线程已经向堆栈添加了另一个项目,在这种情况下,你必须再试一次。
当从堆栈中弹出一个项目时,在返回项目之前,您必须检查另一个线程自操作开始以来没有添加其他项目。
正确性
在某些语言中,特别是那些没有垃圾回收的语言,Treiber栈可能面临ABA问题。当一个进程要从堆栈中移除一个元素时(就在下面的pop例程比较和设置之前),另一个进程可以改变堆栈,使得头部是相同的,但是第二个元素是不同的。比较和交换将堆栈的头部设置为堆栈中旧的第二个元素,混合完整的数据结构。但是,由于Java运行时提供了更强大的保证,所以此页面上的Java版本不受此问题的影响(新创建的不混淆的对象引用不可能与任何其他可到达的对象引用相同)。
对诸如ABA之类的故障进行测试可能会非常困难,因为有问题的事件序列非常少见。
Java示例
下面是Java中Treiber Stack的实现,它基于Java Concurrency in Practice提供的
public class ConcurrentStack<E> {private AtomicReference<Node<E>> top = new AtomicReference<>();public void push(E item) {Node<E> newHead = new Node<>(item);Node<E> oldHead;do {oldHead = top.get();newHead.next = oldHead;} while (!top.compareAndSet(oldHead, newHead));}public E pop() {Node<E> oldHead;Node<E> newHead;do {oldHead = top.get();if (oldHead == null)return null;newHead = oldHead.next;} while (!top.compareAndSet(oldHead, newHead));return oldHead.item;}private static class Node<E> {public final E item;public Node<E> next;public Node(E item) {this.item = item;}}
}
流程分析
PUSH操作
根据上述的描述做图如上,并分析其工作流程。
- 首先单链表保存了各个Stack中的各个元素,成员变量top持有了栈的栈顶元素。
- 当执行push操作时,首先创建一个新的元素为
newHead
,并让该新节点的next
指针指向top
节点(此时top=oldHead
)。 - 最后通过CAS替换
top=newHead
,CAS的交换条件是top=oldHead
。 - 当条件满足后,操作后的状态如下:
POP操作
根据上述的描述做图如上,并分析其工作流程。
- 当执行pop操作时,创建一个新的指针,该指针指向
top
的next
元素。 - 然后通过CAS替换
top=newHead
,CAS的交换条件是top=oldHead
。
3.当条件满足后,操作后的状态如下:
参考:https://en.wikipedia.org/wiki/Treiber_Stack#cite_note-4
Treiber Stack简单分析相关推荐
- FFmpeg源代码简单分析:configure
===================================================== FFmpeg的库函数源代码分析文章列表: [架构图] FFmpeg源代码结构图 - 解码 F ...
- CSipSimple 简单分析
简介 CSipSimple是一款可以在android手机上使用的支持sip的网络电话软件,可以在上面设置使用callda网络电话.连接使用方式最好是使用wifi,或者3g这样上网速度快,打起电话来效果 ...
- 10.JVM内存简单分析
JVM内存简单分析 一.方法区(method) 二.堆栈(stack) 2.1基本变量的存储 2.2对象引用的存储 三.堆(heap) 我见青山多妩媚,料青山见我应如是. 辛弃疾<贺新郎·甚矣吾 ...
- R语言splines包构建基于logistic回归的自然样条分析:南非心脏病数据集、非线性:基函数展开和样条分析、你简单分析的不重要特征,可能只是线性不显著、而非线性是显著的
R语言splines包构建基于logistic回归的自然样条分析:南非心脏病数据集.非线性:基函数展开和样条分析.你简单分析的不重要特征,可能只是线性不显著.而非线性是显著的 目录
- [EntLib]微软企业库5.0 学习之路——第七步、Cryptographer加密模块简单分析、自定义加密接口及使用—上篇...
在完成了后,今天开始介绍企业库中的新模块:Cryptographer(加密模块),这个模块在日常的大多数项目的作用非常重要,例如:网站会员密码.身份证号.网站配置等,通过对信息进行加密可以保证项目数据 ...
- FFmpeg资料来源简单分析:libswscale的sws_getContext()
===================================================== FFmpeg库函数的源代码的分析文章: [骨架] FFmpeg源码结构图 - 解码 FFmp ...
- howdoi 简单分析
对howdoi的一个简单分析. 曾经看到过下面的这样一段js代码: try{doSth(); } catch (e){ask_url = "https://stackoverflow.com ...
- Mac与Phy组成原理的简单分析
Mac与Phy组成原理的简单分析 2011-12-28 15:30:43 //http://blog.chinaunix.net/uid-20528014-id-3050217.html 本文乃fir ...
- python做数据可视化的代码_Python数据可视化正态分布简单分析及实现代码
Python说来简单也简单,但是也不简单,尤其是再跟高数结合起来的时候... 正态分布(Normaldistribution),也称"常态分布",又名高斯分布(Gaussiandi ...
最新文章
- 用PHP代码实现简单的工厂模式,用PHP代码实现简单的工厂模式
- navicat保存查询语句_还在用 Navicat 的,可以试试这几款免费且好用的 MySQL 客户端...
- html / css学习笔记-1
- 苹果几最好用_深度解析安卓手机和苹果手机到底有哪些区别,哪种手机最好用...
- 做一件事情的3个关键指标:兴趣、能力和回报
- Oracle数据库只读事务和无事务的区别
- 11 java基础之继承:区分子类方法中变量的三种变量
- python爬虫怎么发布请求_http请求如何在python爬虫中实现?
- 开启A20线(部分译)
- 互联网搜索的哪些环节 机器学习_机器学习、深度学习以及强化学习在金融领域有哪些应用?...
- NDK编译时指定NDK_MODULE_PATH的方法
- animate.css 官方,animateCSS
- 配置VSS2005的Internet访问(转)
- 【迪文屏】踩坑指南——汉字显示乱码、背景图不显示问题的解决方法
- 计算机到点就有音乐怎么清除缓存垃圾,如何自动清理网易音乐的缓存
- 如何使用注册表在Win10中调整屏幕亮度
- 南卡NEO骨传导首发新机,超前无线充设计,树立行业标杆!!!
- linux centos7.x 编译安装php7.4.2
- 关于订单功能的处理和分析
- 树的概念及存储结构(双亲表示法,孩子表示法,孩子兄弟表示法)