ConcurrentHashMap
Posted renqiqiang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ConcurrentHashMap相关的知识,希望对你有一定的参考价值。
ConcurrentHashMap探究
- ConcurrentHashMap的key和value不能为空
Node
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
volatile V val;
volatile Node<K,V> next;
}
put操作
hash操作
// (h = key.hashCode()) ^ (h >>> 16)
static final int spread(int h) {
//比HashMap多并上了一个HASH_BITS
//HASH_BITS
//static final int HASH_BITS = 0x7fffffff; // usable bits of normal node hash
//HASH_BITS是0x7fffffff,该步是为了消除最高位上的负符号 hash的负在ConcurrentHashMap中有特殊意义表示在扩容或者是树节点
return (h ^ (h >>> 16)) & HASH_BITS;
}
public V put(K key, V value) {
return putVal(key, value, false);
}
//casTabAt主要用于CAS比较该索引处是否为null防止其它线程已改变该值,null则插入,break结束死循环
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);
}
//获取数组i索引的Node CAS操作 保持其它线程对table的改变在这里可见
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);
}
/** Implementation for put and putIfAbsent */
final V putVal(K key, V value, boolean onlyIfAbsent) {
//key或者value为空,抛出空指针异常
if (key == null || value == null) throw new NullPointerException();
//获取hash值
int hash = spread(key.hashCode());
int binCount = 0;
//???
for (Node<K,V>[] tab = table;;) {
Node<K,V> f; int n, i, fh;
//table为null或空map时进行初始化
if (tab == null || (n = tab.length) == 0)
tab = initTable();
// 判断当前索引位置的数组上是否有值 无值那就是首元素插入
//获取数组i索引的Node CAS操作 保持其它线程对table的改变在这里可见
else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
//casTabAt主要用于CAS比较该索引处是否为null防止其它线程已改变该值,null则插入,break结束死循环
if (casTabAt(tab, i, null,
new Node<K,V>(hash, key, value, null)))
break; // no lock when adding to empty bin
}
//首地址处不null 并且Node的hash是-1 表示是ForwardingNode节点正在rehash扩容
else if ((fh = f.hash) == MOVED)
//帮助扩容
tab = helpTransfer(tab, f);
else {
V oldVal = null;
//对桶的首元素上锁独占
synchronized (f) {
if (tabAt(tab, i) == f) {
// 桶中键值对组织形式是链表
if (fh >= 0) {
binCount = 1;
for (Node<K,V> e = f;; ++binCount) {
K ek;
if (e.hash == hash &&
((ek = e.key) == key ||
(ek != null && key.equals(ek)))) {
oldVal = e.val;
// 查找到对应键值对,更新值
if (!onlyIfAbsent)
e.val = value;
break;
}
Node<K,V> pred = e;
// 桶中没有对应键值对,插入到链表尾部
if ((e = e.next) == null) {
pred.next = new Node<K,V>(hash, key,
value, null);
break;
}
}
}
// 桶中键值对组织形式是红黑树
else if (f instanceof TreeBin) {
Node<K,V> p;
binCount = 2;
if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key,
value)) != null) {
oldVal = p.val;
if (!onlyIfAbsent)
p.val = value;
}
}
}
}
// 检查桶中键值对总数
if (binCount != 0) {
//大于固定长度,转换为红黑树
if (binCount >= TREEIFY_THRESHOLD)
treeifyBin(tab, i);
if (oldVal != null)
return oldVal;
break;
}
}
}
// 更新baseCount
addCount(1L, binCount);
return null;
}
以上是关于ConcurrentHashMap的主要内容,如果未能解决你的问题,请参考以下文章
探索 ConcurrentHashMap 高并发性的实现机制
探索 ConcurrentHashMap 高并发性的实现机制