简介
CAS(compare and swap) 即“比较”和“交换”,主要为了解决在多线程并发情况下,使用锁造成的性能消耗问题。在高效、不加锁的情况下,能够以原子性的行为实现数据的操作。一般系统层面都在硬件层次上直接支持CAS指令,而高级语言一般都会直接利用这些指令。
java中的CAS
在java.util.concureent.atomic
包中拥有大量的原子类,他们都是利用了CAS来完成原子性操作。需要关注的就是它们共同都拥有的一个函数compareAndSet(expect,update)
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
以AtomicInteger
类中的compareAndSet
函数为例,其他各个原子类的compareAndSet
函数差异不大。最后调用的都是unsafe.compareAndSwapInt
函数或者unsafe.compareAndSwapObject
只不过一个是数值一个是引用类型而已。
compareAndSet函数
这个函数总共有两个参数,expect
和update
,第一个代表期望值,第二个代表要更新的值。当在更新值时,如果当前的值和期望值相同则进行更新,否则不更新。
比较
与synchronized
想比较,这种原子性的更新方式是另外一种思维。synchronized
是悲观的,它认为在它操作时,极大可能产生冲突,所以先获取锁,让别人无法操作后才进行操作。这种阻塞算法式的方式,的开销是比较大的,它在得不到锁是,需要进入等待锁的Lock池,一直等待其他线程的唤醒,有上下文切换的开销。
而CAS是一种乐观的方式,它假定产生冲突的几率较小。如果发生冲突也没关系,继续尝试就可以。它是非阻塞的,所有有着比synchronized
更高的效率,且性能更高。
ABA问题
使用CAS方式更新,会产生一个ABA的问题。ABA是指,两个线程AB,当B将值修改后又修改回原来的值时,A线程是无法感知到数据是否发生过变化。要解决这个问题,可以使用AtomicStampedReference
来解决,在修改数据时,了外附加一个时间戳,只有时间戳和数据都相同时才会进行更改。
AtomicStampedReference
暂留
来源:oschina
链接:https://my.oschina.net/cuckoocity/blog/4254636