AtomicInteger

CAS: compare and swap 比较并交换

  1. public class CAS01 {
  2. AtomicInteger atomicInteger=new AtomicInteger(5);
  3. public static void main(String[] args) {
  4. CAS01 cas01=new CAS01();
  5. System.out.println(cas01.atomicInteger.compareAndSet(5,2021)+"\t current atomicInteger is :"+cas01.atomicInteger);
  6. System.out.println(cas01.atomicInteger.compareAndSet(5,2008)+"\t current atomicInteger is :"+cas01.atomicInteger);
  7. }
  8. }

静态方法无法访问非静态变量
所以上面如果atomicInteger没有static修饰,就只能如上

  1. public class CAS01 {
  2. public static void main(String[] args) {
  3. AtomicInteger atomicInteger=new AtomicInteger(5);
  4. //main线程do something
  5. System.out.println(atomicInteger.compareAndSet(5,2021)+"\t current atomicInteger is :"+atomicInteger);
  6. System.out.println(atomicInteger.compareAndSet(5,2008)+"\t current atomicInteger is :"+atomicInteger);
  7. }
  8. }

输出:
true current atomicInteger is :2021
false current atomicInteger is :2021

分析:
main线程将主内存中的atomicInteger拷贝到其工作内存,
然后做一些事情
完事之后就将工作内存的值刷新回主内存
此时主内存中的值依旧是5,与期望值5相同,故将主内存中的值改为更新值2021
同时又有一个线程进行相同的操作,但是此时主内存中的值已经更新为2021,与期望值5不一致
故无法将主内存中的值改为更新值2008
上面的这段话就是compare and swap的流程!

unsafe类

  1. unsafe类中存在大量的native方法,因而可以直接调用系统底层资源来执行任务
  2. unsafe类存在于sun.misc包下
  3. cas操作依赖于unsafe中的方法

valueOffset变量

  1. 表示value变量在内存中的偏移地址,比如一个对象有一个起始地址,那对象中的变量有对应的相对于起始地址的偏移地址
  2. unsafe就是根据内存偏移地址获取数据的
  3. image.png

value变量

  1. atomicInteger的初始值就会赋值给value变量(AtomicInteger有参构造方法)
  2. 该变量使用volatile修饰,保证了多线程中的可见性和禁止指令排序,无法保证原子性

三者结合

image.png

CAS

源码

  1. CAS全称compare-and-swap,为一条cpu并发原语,原语本身由多条指令构成,执行时不允许中断
  2. 功能:判断内存某个位置的值是否为预期值,如果是则可以将其更改为更新值,整个过程是原子的
  3. 调用sun.misc.Unsafe类中的cas方法,jvm会帮我们实现cas汇编指令,这是一种完全依赖于硬件的功能,通过它实现原子操作

Unsafe类中的getAndAddInt方法:

  1. public final int getAndAddInt(Object var1, long var2, int var4) {
  2. int var5;
  3. do {
  4. var5 = this.getIntVolatile(var1, var2);
  5. } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
  6. return var5;
  7. }

分析:

  1. 如果AtomicInteger调用getAndIncrement时再调用getAndAddInt
  2. 此时的var和var2分别是AtomicInteger对象和该对象中value变量相对于该对象的偏移地址
  3. var4为1
  4. var5 = this.getIntVolatile(var1, var2)表示从主内存中复制共享变量的值到工作内存
  5. while(…)表示:如果此时主内存中获取的值跟var5相同,则将var加上var4并并更新到主内存,而且返回true,从而退出while循环
  6. 我的理解就是do while的body会拷贝一次值,然后while的判断条件也会拷贝一次值
  7. 即开头讲的cas思想结合do while

原子性保证

image.png
结合cpu并发原语阐述

缺点:

1.循环时间长开销大

do while中的cas如果一直不成功,即返回false
则会一直循环下去
会给cpu带来很大的开销

2.只能保证一个共享变量的原子操作

cas方法参数中只能操作一个共享变量
如果想保证多个共享变量的原子操作,需要使用synchronized

3.ABA问题

image.png

AtomicReference(原子引用)

AtomicInteger对整形进行原子保证
AtomicReference对自定义的类进行原子保证

  1. class User{
  2. private int age;
  3. private String name;
  4. public User(int age,String name){
  5. this.name=name;
  6. this.age=age;
  7. }
  8. public String getName(){
  9. return this.name;
  10. }
  11. }
  12. public class CAS01 {
  13. public static void main(String[] args) {
  14. User z3=new User(21,"zhangsan");
  15. User l4=new User(10,"lisi");
  16. AtomicReference<User> atomicReference=new AtomicReference<>();
  17. atomicReference.set(z3);
  18. System.out.println(atomicReference.compareAndSet(z3,l4)+"\t current atomicReference is :"+atomicReference.get().getName());
  19. System.out.println(atomicReference.compareAndSet(z3,l4)+"\t current atomicReference is :"+atomicReference.get().getName());
  20. }
  21. }

输出:
true current atomicReference is :lisi
false current atomicReference is :lisi

分析参考AtomicInteger
atomicReference多了set和get方法

ABA问题

image.png
image.png