• 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的实现

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

  • 相关阅读:
    【必备】史上最全的浏览器 CSS & JS Hack 手册(转)
    iScroll4.2.5中的无法滑动或点击的解决方案(转)
    无障碍网页设计(WCAG2.0)
    大小端
    TCP报文结构
    A*
    shell中uniq与sort -u 两种去重的对别
    login流程
    类模板成员函数
    game 角色相关记录
  • 原文地址:https://www.cnblogs.com/woooodlin/p/13138710.html
Copyright © 2020-2023  润新知