在看了有关的CAS介绍之后,记录一下CAS的相关知识,作为再查阅。
java利用处理器的CAS(Compare And Swap)指令,循环执行数据比对,直到成功就停止循环。
实际过程:
如果多个线程要对一个变量A(Integer)进行修改,假设变量A初始化值为1,此时线程1要对A进行修改,修改过程,线程1通过传入期望值和修改值,与变量A的初始化值进行匹配。期望值与初始化值匹配成功就将A的值改为修改值;匹配失败就一直循环匹配,直到成功停止。
常用的CAS原子操作类:AtomicInteger,AtomicLong,AtomicReference(引用类型),AtomicIntegerArray/AtomicLongArray(数组类型);
JDK8:新增了:DoubleAccumulator、LongAccumulator、DoubleAdder、LongAdder
借用阿里巴巴的java规范中并发处理13项
LongAdder的具体信息读过一篇文章:
https://blog.csdn.net/f641385712/article/details/84934085
一个小示例:
package com.wuml.thread.cas;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @author by wml on 2019/11/27.
*/
public class AtomicInt extends AtomicInteger{
static AtomicInteger atomicInteger = new AtomicInteger(10);
public static void main(String[] args) {
// 直接获取值
System.out.println(atomicInteger.get());
// 先返回10 然后--> 9
System.out.println(atomicInteger.getAndDecrement());
// 先返回9 然后--> 10
System.out.println(atomicInteger.getAndIncrement());
// 先-->11 然后返回
System.out.println(atomicInteger.incrementAndGet());
}
}
经过网上的查阅:
CAS的问题大概归为3类:
1、ABA问题
如果另一个线程修改V值,假设原来是A,先修改成B后又修改回A,当前线程的CAS操作无法分辨V是否变化。
jdk中提供了2个版本号记录的类解决这个问题:
AtomicStampedReference(stamp修改了变量就增加)
AtomicMarkableReference(以布尔型确认是否修改变量)
2、只能保证一个共享变量的原子操作
3、开销问题,当CAS一直匹配不成功时,一直自旋进行CAS操作。
只要是谈及多个线程对同一个变量的访问,就会想到synchronized;
synchronized:是基于阻塞式的锁机制;被阻塞的线程优先级高,大量的线程竞争锁会消耗CPU,可能会出现死锁等情况。
synchronized是属于内置锁,当然会有显式锁,后面继续记录显式锁Lock与synchronized的区别与实践。