ConcurrentHashMap 中为了提高并发时锁的效率,对底层做了很多优化,其中一点就是对存储数据的数组的操作的优化,在Java 8中使用了 CAS 对要操作的数组进行操作
Unsafe 的获取
Field f = Unsafe.class.getDeclaredField("theUnsafe"); f.setAccessible(true); Unsafe unsafe = (Unsafe) f.get(null);
存储数据数组的获取
在高并发环境下,直接以index的形式对数据的元素进行各种操作是不安全的,而直接对元素数组进行加锁,控制读取,则效率低,吞吐量下降。就像拆分解决问题的概念一样,ConcurrentHashMap 采用 lock-free的形式具体操作每个元素。为了实现这种粒度,需要使用 Unsafe 工具集中的一下几个方法
// 数组对象的起始 offset
long ABASE = unsafe.arrayBaseOffset(Class)
// 对象的每个元素的长度,(boolean 1, char 2, short 2, int 4, reference 4, float 4, double 8, long 8)
int scale = unsafe.arrayIndexScale(Class)
// 需要移动的位数,如果数组元素是 int类型,则ASHIFT 为 2,即元素的偏移量为 ABASE + (1 << ASHIFT) * i. 第一个元素为 ABASE + 4; 第二个元素的偏移量为 ABASE + 8
int ASHIFT = 31 - Integer.numberOfLeadingZeros()
// 使用 unsafe 以原子化的形式读取数组的第 i 个元素
static final <K,V> Node<K,V> tabAt(Node<K,V>[] tab, int i) {
return (Node<K,V>)U.getObjectVolatile(tab, ((long)i << ASHIFT) + ABASE);
}
数组元素的插入
static final <K,V> void setTabAt(Node<K,V>[] tab, int i, Node<K,V> v) { U.putObjectVolatile(tab, ((long)i << ASHIFT) + ABASE, v); }
数组元素的更新
static final <K,V> boolean casTabAt(Node<K,V>[] tab, int i, Node<K,V> c, Node<K,V> v) { return U.compareAndSwapObject(tab, ((long)i << ASHIFT) + ABASE, c, v); }
Patience is always a virtue that worth your effort.
The usefulness of a cup is its emptiness.
浙公网安备 33010602011771号