链表长度超过8,Node数组超过64时会将链表结构转换为红黑树,Node对象
1.8 ConcurrentHashMap put画图参考
看一下ConCurrentHashMap 是如何处理putValue的
/** Implementation for put and putIfAbsent */
final V putVal(K key, V value, boolean onlyIfAbsent) {
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;
if (tab == null || (n = tab.length) == 0)
tab = initTable();
//拿取存放的位置,如果该位置为空,则进行cas操作,将空换成node对象,tabAt拿值时是用了Unsafe的getObjectVolatile,保证最新引用值
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
}
else if ((fh = f.hash) == MOVED)
//扩容操作
tab = helpTransfer(tab, f);
else {
V oldVal = null;
//当f = tabAt(tab, i = (n - 1) & hash)不为空时,以这个对象加锁
synchronized (f) {
//判断对象是否相等
if (tabAt(tab, i) == f) {
if (fh >= 0) {
binCount = 1;
//死循环,每次binCount加1
for (Node<K,V> e = f;; ++binCount) {
K ek;
//判断key值equals或者是否相等,相等覆盖
if (e.hash == hash &&
((ek = e.key) == key ||
(ek != null && key.equals(ek)))) {
oldVal = e.val;
if (!onlyIfAbsent)
e.val = value;
break;
}
//尾插法,当e.next==null时,插入数据
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;
}
tabAt源码
/* ---------------- Table element access -------------- */
/*
* Volatile access methods are used for table elements as well as
* elements of in-progress next table while resizing. All uses of
* the tab arguments must be null checked by callers. All callers
* also paranoically precheck that tab's length is not zero (or an
* equivalent check), thus ensuring that any index argument taking
* the form of a hash value anded with (length - 1) is a valid
* index. Note that, to be correct wrt arbitrary concurrency
* errors by users, these checks must operate on local variables,
* which accounts for some odd-looking inline assignments below.
* Note that calls to setTabAt always occur within locked regions,
* and so in principle require only release ordering, not
* full volatile semantics, but are currently coded as volatile
* writes to be conservative.
*/
@SuppressWarnings("unchecked")
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);
}
tabAt拿值时是用了Unsafe的getObjectVolatile,保证拿到最新引用值
table变量加了volatile,但也只能保证其引用的可见性,并不能确保其数组中的对象是否是最新的,所以需要Unsafe类volatile式地拿到最新的Node(摘自参考)
小总结:
当多线程参与竞争时,命中同一个位置时,会对当前node头做锁操作,而且不会对数组其他的位置造成影响。
扩容内容挺多,下节在看及画图
参考
ConcurrentHashMap是如何实现线程安全的
ConcurrentHashMap
Java容器(二)-CurrentHashMap详解(JDK1.8)