java cas 同步_Java线程之同步替代方案CAS

1.并发系统的同步机制

在设计并发系统的时候,设计同步机制是极为重要的一环。

同步机制就是保证状态安全,保证状态的原子性、可见性和有序性。

最常见的同步机制是使用悲观锁。即使用synchronized、ReentrantLock等工具来实现同步。在这种方案下,如果发生了竞争,一些线程就要被操作系统挂起,在稍后又要恢复运行。操作系统在挂起和恢复线程的过程中存在很大的开销。

与锁相比,volatile是一种更轻量级的同步机制。但是volatile的使用场景局限性很大:它不能用于构建原子的复合操作,就是只能保证一个状态变量同步;它也不能用于新值依赖旧值的情况。

除了这两种情况,还有第三种方案:Compare and Swap,简称CAS。CPU支持很多原子指令,比如:测试并设置(Test-and-Set),获取并递增(Fetch-and-Increment),交换(Swap),比较并交换(Compare-and-Swap)…… CAS正是CPU的一个原子指令。但是,并不是每一种CPU架构都实现了CAS。

CAS包含了3个操作数——需要读写的内存位置V,进行比较的值A和拟写入的新值B。当且仅当V的值等于A时,CAS才会通过原子的方式用新值B来更新V的值。可以把CAS看做一把乐观锁。CAS的典型使用模式是:首先从V中读取值A,并根据A计算新值B,然后再通过CAS以原子方式将V中的值由A变成B。

而且,CAS的性能会随着CPU数量的不同而不同。因为CPU之间要进行同步,所以CPU越多,CAS性能越差。

CAS可能会存在ABA问题,如果V的值首先由A变成B,再由B变成A,这仍然发生了变化,但是可以更新成功。这个问题可以引入版本号来解决:每修改一次,内存的版本号就更新一次,比价的时候带上版本号即可。

当多个线程使用CAS同时更新一组状态变量时,只有一个线程能更新变量的值,而其他线程都将失败。失败的线程不会被挂起,而是返回失败结果,让应用程序开发者处理。开发者可以重试,也可以进行一些恢复操作,也可以直接放弃……这样其实有利有弊:

利:CAS是CPU指令,效率肯定比操作系统层面的锁机制高。然后CAS不需要挂起线程,所以就没有挂起和恢复线程的开销。获取一把无竞争的锁的开销大约是CAS操作的开销的两倍。

弊:竞争失败的善后操作由开发者提供,会增加程序的复杂度;在竞争很激烈的情况下,善后操作会变得很多,直接降低性能。

所以,在竞争程度较高的情况下锁的性能反而可能会更好。而且使用CAS开发的复杂度会比使用锁高很多,建议直接使用由开发专家开发好的基于CAS的并发系统,应用开发者不要随便使用CAS进行开发。

2.Java中用CAS实现的非阻塞算法

从Java 8之后,ConcurrentHashMap、ConcurrentLinkedDeque、ConcurrentLinkedQueue、ConcurrentSkipListMap、ConcurrentSkipListSet内部都使用了CAS实现了非阻塞算法。以ConcurrentHashMap为例,在Java 8之前是使用分段锁的方法实现的并发,Java 8改成了使用CAS。这些类都是由开发专家实现的,我们当然可以放心用,而且性能肯定不错。

3.原子变量类

CAS是CPU指令,所以如果Java平台不做支持,Java开发者是没办法使用CAS的。从Java 5开始,Java平台提供了原子变量类,在int、long和对象的引用等类型上都公开了CAS操作。这样,让我们Java开发者也能一定程度上使用CAS设计并发系统。但是不是所有的CPU都支持CAS指令,这时JVM将使用自旋锁。

共有12个原子变量,可分为4组:标量类、更新器类、数组类以及复合变量类:

标量类:AtomicBoolean、AtomicInteger、AtomicLong。其他基本类型可以先转化成int或long,再使用原子变量类。

更新器类:AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicReferenceFieldUpdater。基于反射对非原子类进行原子更新。

数组类:AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray。可以对数组里面的元素进行原子操作。

复合变量:AtomicReference、AtomicMarkableReference、AtomicStampedReference。对普通对象进行原子操作。后面两个可以防止ABA问题。

总结:

CAS适合于竞争程度不高的场合(事实上大部分并发系统都是为了实现业务,竞争都不会很高,不会故意引入大量竞争);

CAS设计的系统复杂度比锁实现的系统高,所以Java开发者不要使用CAS开发太复杂的并发系统。在 Java平台中很多非阻塞算法都由CAS实现,Java开发者可以直接使用;

CAS是CPU指令,Java开发者不能直接使用,可以借助Java平台公开的原子变量类使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值