atomic原子类的理解

1.AtomicInteger等原子类的底层都是由Unsafe类的CAS思想和自旋锁实现。

2.CAS思想是把自己的期望值和主存中的值进行比较,如果相同就赋值,不同就不赋值。CAS是CPU原语,是操作系统底层一系列指令实现,这些指令是连续的,所以是原子的。一般用到CAS的地方都有自旋,即先从主存中获取到值,然后执行CAS,如果主存中的值与刚获取的值相等,就赋要更新的值(下表中的update)。

1、//这是AtomicInteger类的CAS
public final boolean compareAndSet(int expect, int update) {//expect是期望值,用来与主存中的值进行比较,如果相同就把主存中的值改成update return unsafe.compareAndSwapInt(this, valueOffset, expect, update);//底层是调用unsafe类中的nativa方法 }
2.//这个是AtomicInteger类中的获取并加1的方法
public final int getAndIncrement() {
    //调用unsafe类中方法,valueOffset是这个对象在主存中的地址变量,也叫地址偏移量
    return unsafe.getAndAddInt(this, valueOffset, 1);
}
/**
 *调用的unsafe类中源码
 *其实是先从主存中获值,然后再执行CAS,如果比较不相同,再从新获取值,执行CAS,一 
 * 直自旋
 */
public final int getAndAddInt(Object var1, long var2, int var4) {
   int var5;
   do {//利用do-while自旋
       var5 = this.getIntVolatile(var1, var2);//从主存中获取值
   } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));//执行CAS

   return var5;
}

3.CAS与Sychronized的比较

  Synchronized是对一个对象加锁,锁的是整个对象,数据一致性可以保证,但并发性降低;

  而CAS没有用锁,是使用自旋的方式,先从内存中取值,然后再比较赋值,并发性和数据一致性都有了保证

4.CAS的缺点:

  ①CAS使用的是自旋,CPU消耗大

  ②CAS引来了ABA问题:即t1和t2两个线程都在执行修改主存中的值A(都现将A拷到了本线程的工作内存中),某一时刻t2线程先将A改成了B(此时主存中变成了B),然后又将B改成了A(主存中又变成了A),然后t1线程执行CAS,compareAndSwap(A,C),一比较,认为主存中的值和期望值相同,所以就将主存中的值改成了C,此时t1线程却不知主存中的值经历了A-B-A的过程。这种问题的解决办法是:使用原子包中的AtomicStampedReference时间戳(又叫版本号)原子引用可以解决,即为主存中的值设置一个版本号,每次CAS时不仅比较值,还要比较版本号,都相同再赋值

——每天一小步,进步一大步,坚持。。。

 

 

 

 

posted @ 2020-12-19 18:34  发奋推墙  阅读(200)  评论(0编辑  收藏  举报