多线程同步工具——CAS原子变量
这是我参考的一篇文章《基于CAS的乐观锁实现》,讲述的是一种需要CPU支持的执行技术CAS(Compare and Swap)。
首先理解什么是原子性操作,意思是不能再拆分的操作,例如改写一个值,读取一个值都属于原子性操作。
那么CAS是两个操作,先比较旧值,比较通过后再进行改写,这种连合操作合并成一个指令交给CPU,由CPU操作来确保这是一个原子性操作。
多线程同时改写同一个值时,每个线程携带自己的旧值和新值交给CPU改写,CPU的运行是按逐条指令运行,如果发现旧值不符合,线程就会收到改写失败回应。
public final int incrementAndGet() {
    for (;;) {
        int current = get();
        int next = current + 1;
        if (compareAndSet(current, next))
            return next;
    }
}
因此AtomicInteger#incrementAndGet()方法里,会循环尝试使用compareAndSet(...)方法,直到成功为止。
相关的原子类所在包:java.util.concurrent.atomic
- Atomic + Boolean/Integer/Long/Reference
操作一个对应的类型对象 Atomic + Integer/Long/Reference + Array
操作一个对应类型的数组- Atomic + Integer/Long/Reference + FieldUpdater
操作一个对应类型的Field对象,类似反射方式改写对象字段 
这里《AtomicStampedReference解决ABA问题》,讲述了原子类会出现ABA时带来的隐患,文中举了一个例子,一个单向的链表实现了堆栈操作,使用一个原子变量作为链头指针,现在链头是A,A的next是B。有两个线程分别是T1和T2,他们并发的操作如下:
- T1:AB => B
 - T2:AB => B => 空 => D => CD => ACD
 
由于线程T1只认链头是不是A,如果是A,就会将链头指向B,因此可能会出现直接把ACD变成B,这就是ABA并发的隐患。
- AtomicMarkableReference
操作一个对象类型和boolean类型的二元组 - AtomicStampedReference
操作一个对象类型和int类型的二元组 
虽然例子中链头指针是一个原子变量,会出现ABA的情况,但如果再增加一个原子变量,这个原子变量确保不会出现ABA的情况,两个原子变量作为二元组进行原子性操作,即使用AtomicStampedReference就可以有效解决这个ABA的隐患了。
以下是Java8增加的原子类:
- Striped64
 - Long/Double + Adder
 - Long/Double + Accumulator
 
这里有两篇文章,内容是分析它们的源码:《从LongAdder 看更高效的无锁实现》,《LongAdder和LongAccumulator》
源码有些复杂,我也没看完,Striped64是这项新原子类的基类,它提供的原理是,把一个原子数拆分成多个原子数,最后把这多个原子数合成一个数。换句话说,原本在一个数上做递增或者递减操作的,现在变成在多个数里,选择其中一个做做递增或递减操作,那么加起来的结果与原本方式的结果是等价的。虽然是等价,但它结算结果的过程,是需要把多个数加起来,这个过程已经不是线程安全了,所以它的应用场合相比原本方式会宽一点,原本方式所取出来的值可以作为唯一ID,但现在方式只能用于统计。试想,如果有1000个线程同时在统计同一个数据,那么原本方式的原子类,就会失败率上升,效率也会随之下降。但如果把1000个线程,分成10份,每100个线程统计同一个数据,那么产生10个数据,最后统计的结果就是这10个数据叠加一起的结果,失败率当然因份数的增加而减少,效率也自然有保障。
应用场合:高并发,统计数据。
多线程同步工具——CAS原子变量的更多相关文章
- 多线程同步工具——volatile变量
		
关于volatile,找了一堆资料看,看完后想找一个方法去做测试,测了很久,感觉跟没有一样. 这本书<深入理解Java内存模型>,对volatile描述中有这样一个比喻的说法,如下代码所示 ...
 - Java多线程并发编程之原子变量与非阻塞同步机制
		
1.非阻塞算法 非阻塞算法属于并发算法,它们可以安全地派生它们的线程,不通过锁定派生,而是通过低级的原子性的硬件原生形式 -- 例如比较和交换.非阻塞算法的设计与实现极为困难,但是它们能够提供更好的吞 ...
 - Java多线程同步工具类之CountDownLatch
		
在过去我们实现多线程同步的代码中,往往使用join().wait().notiyAll()等线程间通信的方式,随着JUC包的不断的完善,java为我们提供了丰富同步工具类,官方也鼓励我们使用工具类来实 ...
 - Java多线程同步工具类之Semaphore
		
Semaphore信号量通常做为控制线程并发个数的工具来使用,它可以用来限制同时并发访问资源的线程个数. 一.Semaphore使用 下面我们通过一个简单的例子来看下Semaphore的具体使用,我们 ...
 - C++11 多线程同步 互斥锁 条件变量
		
在多线程程序中,线程同步(多个线程访问一个资源保证顺序)是一个非常重要的问题,Linux下常见的线程同步的方法有下面几种: 互斥锁 条件变量 信号量 这篇博客只介绍互斥量和条件变量的使用. 互斥锁和条 ...
 - 多线程同步工具——Lock
		
本文原创,转载请注明出处. 参考文章: <"JUC锁"03之 公平锁(一)> <"JUC锁"03之 公平锁(二)> 锁分独占锁与共享锁, ...
 - Java多线程同步工具类之CyclicBarrier
		
一.CyclicBarrier使用 CyclicBarrier从字面上可以直接理解为线程运行的屏障,它可以让一组线程执行到一个共同的屏障点时被阻塞,直到最后一个线程执行到指定位置,你设置的执行线程就会 ...
 - 多线程同步工具——LockSupport
		
用例1:子线程等待主线程发放许可! public static void main(String[] args) { Thread thread = new Thread(){ public void ...
 - Java多线程-----原子变量和CAS算法
		
原子变量 原子变量保证了该变量的所有操作都是原子的,不会因为多线程的同时访问而导致脏数据的读取问题 Java给我们提供了以下几种原子类型: AtomicInteger和Ato ...
 
随机推荐
- 【深入浅出jQuery】源码浅析--整体架构
			
最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...
 - 阿里云服务器上配置并使用: PHP + Redis + Mysql  从配置到使用
			
(原创出处为本博客,http://www.cnblogs.com/linguanh/) 目录: 一,下载 二,解压 三,配置与启动 四,测试 Redis 五,配置 phpRedis 扩展 六,综合测试 ...
 - HTML5轻松实现搜索框提示文字点击消失---及placeholder颜色的设置
			
在做搜索框的时候无意间发现html5的input里有个placeholder属性能轻松实现提示文字点击消失功能,之前还傻傻的在用js来实现类似功能... 示例 <form action=&quo ...
 - FullCalendar应用——整合农历节气和节日
			
FullCalendar用来做日程管理功能非常强大,但是唯一不足的地方是没有将中国农历历法加进去,今天我将结合实例和大家分享如何将中国农历中的节气和节日整合到FullCalendar中,从而增强其实用 ...
 - Div Vertical Menu ver5
			
这个小功能,如果是算此次,已经是第5次修改了.可以从这里看到前4次:V1, http://www.cnblogs.com/insus/archive/2011/10/17/2215637.html V ...
 - spring applicationContext.xml和hibernate.cfg.xml设置
			
applicationContext.xml配置 <?xml version="1.0" encoding="UTF-8"?> <beans ...
 - 使用git进行源代码管理
			
git是一款非常流行的分布式版本控制系统,使用Local Repository追踪代码的修改,通过Push和Pull操作,将代码changes提交到Remote Repository,或从Remote ...
 - 技术笔记:XMPP之openfire+spark+smack
			
在即时通信这个领域目前只找到一个XMPP协议,在其协议基础上还是有许多成熟的产品,而且是开源的.所以还是想在这个领域多多了解一下. XMPP协议:具体的概念我就不写了,毕竟这东西网上到处是.简单的说就 ...
 - Xamarin.Android广播接收器与绑定服务
			
一.前言 学习了前面的活动与服务后,你会发现服务对于活动而言似乎就是透明的,相反活动对于服务也是透明的,所以我们还需要一中机制能够将服务和活动之间架起一座桥梁,通过本节的学习,你将会学到广播与绑定服务 ...
 - 让Mono 4在Raspberry Pi上飞
			
最近公司有项目想要在树莓派上做,代替原来的工控机(我们是把工控主机当作小的主机用,一台小的工控主机最少也要600左右,而树莓派只要200多).于是,公司买了一个Raspberry Pi B+和一个Ra ...