CAS
CAS(Compare And Swap)是由硬件实现的.
可以将read modify write 这类的操作转换为原子操作。 i++自增操作包括三个子操作: 从主内存读取i的变量值
加1 再把加一之后的值保存到主内存.
原理
在把数据更新到主内存时,再次读取主内存变量的值,如果现在变量的值与期望的值(操作起始时读 取的值)一样就更新.
前提
CAS实现原子操作的背后有一个假设:
共享变量的当前值与当前线程提供的期望值相同,就认为这个变量没有被其他线程修改过。 实际上这种假设不一定成立。
如:共享变量count=0 A线程对值修改为10 B线程修改为20 C线程修改为0; 当前线程看到count变量的值现在是0 ,现在是否认为count的值没有别其他线程更新呢?这种结果是否能够接受; 这就是CAS中的ABA 问题,即共享变量经历了A->B->A的更新; 是否能够接受ABA问题跟实现的算法有关;
如果想规避ABA问题,可以为共享变量引入一个修订号,每次修改共享变量时,响应的修订号就更新,每次对共享变量的修改都会导致修订号的增加,通过修订号来准确判断变量是否被其他线程修改过。 AtomicStampedReference类就是基于这种思想产生的。
原子变量类
基于CAS实现的,当对共享变量进行reda-modify-write更新操作时,通过原子变量类可以保障操作的原子性与可见性。对变量的
reda-modify-write的更新操作不是一个简单的赋值, 而是变量的新值依赖变量的旧值。
如:
自增i++
由于volatile只能保证可见性,无法保证原子性,原子变量内部就是借助一个volatile变量,并且保障了该变量的操作原子性,有时把原子变量类看作是增强的volatile变量。
分组 | 原子变量类 |
---|---|
基础数据型 | AtomicInteger, AtomicLong, AtomicBoolean |
数组型 | AtomicIntegerArray, AtomicLongArray,AtomicReferenceArray |
字段更新器 | AtomicIntegerFieldUpdater,AtomicLongFieldUpdater, AtomicReferenceFieldUpdater |
引用型 | AtomicReference, AtomicStampedReference, AtomicMarkableReference |
例:
-
AtomicIntegerArray :原子更新数组
-
AtomicIntegerFieldUpdater:可以对原子整数字段进行更新
要求: a、字段必须使用volatitle修饰,使线程之间可见 b、只能使实例变量,不能是静态变量,也不能使用final修饰
-
AtomicReference :可以原子读写一个对象 ,但是会出现ABA问题
-
AtomicStampedReference:可以解决ABA问题(加时间戳)
-
AtomicMarkableReference:可以解决ABA问题(加一个标志)