java并发编程实战《二十一》无锁工具类

不安全的累加代码,如下

1 public class Test {
2   long count = 0;
3   void add10K() {
4     int idx = 0;
5     while(idx++ < 10000) {
6       count += 1;
7     }
8   }
9 }

  不安全的原因是count的可见性以及count += 1的原子性

使用AtomicLong

 1 public class Test {
 2   AtomicLong count = 
 3     new AtomicLong(0);
 4   void add10K() {
 5     int idx = 0;
 6     while(idx++ < 10000) {
 7       count.getAndIncrement();
 8     }
 9   }
10 }

好处:

     性能提升

原理:

     硬件支持。CPU 为了解决并发问题,提供了 CAS 指令(CAS,全称是 Compare And Swap,即“比较并交换”)。

  CAS 指令包含 3 个参数:共享变量的内存地址 A、用于比较的值 B 和共享变量的新值 C并且只有当内存中地址 A 处的值等于 B 时,才能将内存中地址 A 处的值更新为新值 C。作为一条 CPU 指令,CAS 指令本身是能够保证原子性的。

源码:

1 final long getAndIncrement() {
2   return unsafe.getAndAddLong(
3     this, valueOffset, 1L);
4 }

  思考:这里为什么要传this?来看一下AtomicLong这个类的结构

 

 

   重点看成员变量getAndAddLong传this和offset肯定是为了获取这个value值,但是为什么不直接传value?实际上这就是引用传值和非引用传值,value是成员变量,从共享内存读,如果直接非引用传值,那在value传入后加入内存屏障之前共享内存中value的值被修改了怎么办?

源码:

 1 public final long getAndAddLong(
 2   Object o, long offset, long delta){
 3   long v;
 4   do {
 5     // 读取内存中的值
 6     v = getLongVolatile(o, offset);
 7   } while (!compareAndSwapLong(
 8       o, offset, v, v + delta));
 9   return v;
10 }
11 //原子性地将变量更新为x
12 //条件是内存中的值等于expected
13 //更新成功则返回true
14 native boolean compareAndSwapLong(
15   Object o, long offset, 
16   long expected,
17   long x);

总结:

  原子类针对单个共享变量,多个共享变量使用互斥锁

以上,还没说完,

  另外还有CAS的ABA问题

等等搞一下openjdk的源码编译,看看compareAndSwapLong的实现

  太特么打击人了,想编译成功太耗费时间,先抛了。

posted @ 2020-06-16 00:15  夜旦  阅读(201)  评论(0编辑  收藏  举报