首先 ConcurrentHashMap 是可以解决并发安全问题的容器
HashMap在并法操作下会出现各种各样的问题
HashTable也解决了兵法问题,但一锁就是整张表
代码也比较清楚
通过key得到hash,定位table中的位置
再去遍历当前Entry下的链表,存在相同的key就覆盖就值,不存在就通过头插法添加一个节点
再看看ConcurrentHashMap通过什么方法解决并发安全问题的
JDK 1.7是采用了分段锁,相较于HashTable降低了锁的粒度,提升了并发度
再看下JDK 1.8的做法,核心思路是 CAS + 锁头节点
这样的话就只锁一个链表或者红黑树
put核心代码:
final V putVal(K key, V value, boolean onlyIfAbsent) {
// key、value 不允许为空
if (key == null || value == null) throw new NullPointerException();
int hash = spread(key.hashCode());
int binCount = 0;
for (Node<K,V>[] tab = table;;) {
Node<K,V> f; int n, i, fh;
// 初始化table
if (tab == null || (n = tab.length) == 0)
tab = initTable();
else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
if (casTabAt(tab, i, null,
new Node<K,V>(hash, key, value, null)))
break; // no lock when adding to empty bin. CAS 初始化头节点
}
else if ((fh = f.hash) == MOVED)
tab = helpTransfer(tab, f);
else {
V oldVal = null;
synchronized (f) { // 锁头节点
if (tabAt(tab, i) == f) { //double check下
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;
}
}
}
addCount(1L, binCount);
return null;
}
看一些核心成员变量
控制table初始化和扩容状态的
/**
* Table initialization and resizing control. When negative, the
* table is being initialized or resized: -1 for initialization,
* else -(1 + the number of active resizing threads). Otherwise,
* when table is null, holds the initial table size to use upon
* creation, or 0 for default. After initialization, holds the
* next element count value upon which to resize the table.
*/
private transient volatile int sizeCtl;
定义的特殊hash值
static final int MOVED = -1; // hash for forwarding nodes
static final int TREEBIN = -2; // hash for roots of trees
static final int RESERVED = -3; // hash for transient reservations
static final int HASH_BITS = 0x7fffffff; // usable bits of normal node hash
转载请注明:汪明鑫的个人博客 » ConcurrentHashMap 1.7和1.8的区别
说点什么
您将是第一位评论人!