Java 为什么ConcurrentHashMap没有';t使用';CAS&x27;但是使用';同步';当tabAt[i]不为空时 final V putVal(K键,V值,仅布尔值){ 如果(key==null | | value==null)抛出新的NullPointerException(); int hash=spread(key.hashCode()); int binCount=0; 对于(节点[]选项卡=表;;){ 节点f;int n,i,fh; 如果(tab==null | |(n=tab.length)==0) tab=initTable(); else if((f=tabAt(tab,i=(n-1)&散列))==null){ 如果(casTabAt,i,空, 新节点(哈希、键、值、null))) break;//添加到空箱子时没有锁 } else if((fh=f.hash)==MOVED) tab=帮助转移(tab,f); 否则{ V oldVal=null; 已同步(f){ if(tabAt(tab,i)==f){ 如果(fh>=0){ binCount=1; 对于(节点e=f;;++binCount){ 凯克; 如果(e.hash==hash&& ((ek=e.key)=key|| (ek!=null&&key.equals(ek))){ oldVal=e.val; 如果(!onlyFabSent) e、 val=值; 打破 } 节点pred=e; 如果((e=e.next)==null){ pred.next=新节点(散列、键、, 值,空); 打破 } } } else if(树的f实例){ 节点p; binCount=2; if((p=((TreeBin)f).putTreeVal(散列,键, 值)!=null){ oldVal=p.val; 如果(!onlyFabSent) p、 val=值; } } } } if(binCount!=0){ 如果(binCount>=树型\u阈值) treeifyBin(表一); 如果(oldVal!=null) 返回oldVal; 打破 } } } 添加计数(1L,二进制计数); 返回null;
}Java 为什么ConcurrentHashMap没有';t使用';CAS&x27;但是使用';同步';当tabAt[i]不为空时 final V putVal(K键,V值,仅布尔值){ 如果(key==null | | value==null)抛出新的NullPointerException(); int hash=spread(key.hashCode()); int binCount=0; 对于(节点[]选项卡=表;;){ 节点f;int n,i,fh; 如果(tab==null | |(n=tab.length)==0) tab=initTable(); else if((f=tabAt(tab,i=(n-1)&散列))==null){ 如果(casTabAt,i,空, 新节点(哈希、键、值、null))) break;//添加到空箱子时没有锁 } else if((fh=f.hash)==MOVED) tab=帮助转移(tab,f); 否则{ V oldVal=null; 已同步(f){ if(tabAt(tab,i)==f){ 如果(fh>=0){ binCount=1; 对于(节点e=f;;++binCount){ 凯克; 如果(e.hash==hash&& ((ek=e.key)=key|| (ek!=null&&key.equals(ek))){ oldVal=e.val; 如果(!onlyFabSent) e、 val=值; 打破 } 节点pred=e; 如果((e=e.next)==null){ pred.next=新节点(散列、键、, 值,空); 打破 } } } else if(树的f实例){ 节点p; binCount=2; if((p=((TreeBin)f).putTreeVal(散列,键, 值)!=null){ oldVal=p.val; 如果(!onlyFabSent) p、 val=值; } } } } if(binCount!=0){ 如果(binCount>=树型\u阈值) treeifyBin(表一); 如果(oldVal!=null) 返回oldVal; 打破 } } } 添加计数(1L,二进制计数); 返回null;,java,concurrenthashmap,Java,Concurrenthashmap,} 当tabAt(tab,i=(n-1)&hash))为null时,它使用CAS添加/修改节点,但当不为null时,它使用同步(f)。我认为它仍然可以使用最后一个节点的CA或需要放入tabAt(tab,I=(n-1)&hash))键的节点来添加/修改节点。但为什么不呢?我的想法是错误的。如果f存在,那么它将遍历并修改树或列表数据结构。这不可能以原子方式就地完成,因此他们需要在整个过程中进行一次写时拷贝(最终CAS可能会导致在concurreny面前重新进行拷贝),或者用一个同步块锁定整个结构。你
当
tabAt(tab,i=(n-1)&hash))
为null
时,它使用CAS添加/修改节点,但当不为null时,它使用同步(f)
。我认为它仍然可以使用最后一个节点的CA或需要放入tabAt(tab,I=(n-1)&hash))
键的节点来添加/修改节点。但为什么不呢?我的想法是错误的。如果f
存在,那么它将遍历并修改树或列表数据结构。这不可能以原子方式就地完成,因此他们需要在整个过程中进行一次写时拷贝(最终CAS可能会导致在concurreny面前重新进行拷贝),或者用一个同步块锁定整个结构。你能发布到源代码的链接吗?这些东西在JDK版本之间会发生变化。
final V putVal(K key, V value, boolean onlyIfAbsent) {
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;
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
}
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;
}
}
}
addCount(1L, binCount);
return null;