Striped64源码解析
Striped64类介绍
Striped64是Java8中新增用来支持累加器的并发组件。它可以在并发环境下做一个安全的计数器。它的设计思路,借鉴了JAVA7中的ConcurrentHashmap的分段思想,在竞争的时候,尽量分散竞争。从实现上来看,Striped64维护了一个base和一个Cell数组。在竞争不激烈的时候,累加器的值就一直在base上累加。竞争激烈的时候,就会通过Cell数组来分散技术。Striped64根据线程计算他们的哈希值,将各个线程分散到不同的Cell中累加。最后的总数,只要结合base以及散落在Cell数组中的计数内容。
Striped64采用了更为轻量级的CAS来协调并发,效率更佳。
类图
主要属性
1 | /** Number of CPUS, to place bound on table size */ |
NCPU:当前运行主机的CPU核数
cells:初始化值为null,没有竞争的情况下,不会使用到这个数组。有了竞争之后,第一次初始化的长度为2,后续每次扩容,都是原来长度的两倍,直到数组长度大于等于当前服务器CPU的数量为止。每个线程会通过线程对cells[threadLocalRandomProbe%cells.length]位置的Cell对象中的value做累加,这样相当于将线程绑定到了cells中的某个Cell对象上。
base:作用类似于AtomicLong中的value,没有竞争的情况下,就对这个值进行增或减。
cellsBusy:它有两个值0或1,它的作用是当要修改cells数组时加锁,防止多线程同时修改cells数组(也称cells表),0为无锁,1为加锁,加锁的状况有三种:
- cells数组初始化的时候;
- cells数组扩容的时候;
- 如果cells数组中某个元素为null,给这个位置创建新的Cell对象的时候;
UNSAFE:JDK提供的CAS算法工具类。
BASE:base字段在当前类中的内存偏移量
CELLSBUSY:cellsBusy字段在当前类中的内存偏移量
PROBE:标记位。标记当前线程是否已经初始化
主要方法
Striped64()
1 | /** |
默认的构造函数。什么都不做。
casBase(long,long)
1 | /** |
如果当前值等于cmp,就把base的值更新为val,cas更新base字段的值。
casCellsBusy()
1 | /** |
将标记位casCellsBusy标记为1.采用cas,如果当前值是0,则标记成功。否则返回false。
getProbe()
1 | /** |
返回当前线程的probe值。
longAccumulate(long,LongBinaryOperator,boolean)
1 | /** |
DoubleAccumulate(double,DoubleBinaryOperator, boolean)
1 | /** |
doubleAccumulate基本上和longAccumulate差不多,它多了Double转长整型和长整型转Double的步骤。