关于ConcurrentHashMap的putVal方法源码的困惑
A confusion about the source code for ConcurrentHashMap's putVal method
这里是 putVal
方法的部分代码:
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(); // lazy Initialization
//step1,tabAt(...) is CAS
else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
//step2,casTabAt(...) is CAS
if (casTabAt(tab, i, null,
new Node<K,V>(hash, key, value, null)))
break; // no lock when adding to empty bin
}
...
return null;
}
假设当前有两个线程,A
和B
,当A
执行step1
时,得到true
,但是在同时 B
也执行 step1
并得到 true
。 A
和 B
都执行 step2
。
从这种情况来看,B
的Node
替换了A
的Node
,或者说A
的数据被[替换了=13=], 这是错误的。
不知道对不对,谁能帮我解决一下?
以下是 casTabAt
的实现方式:
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);
}
而 U
声明如下:private static final sun.misc.Unsafe U;
。此 class 的方法保证了低级别的原子性 。从这个用法来看:
casTabAt(tab, i, null, new Node<K,V>(hash, key, value, null))
我们可以看到,assuming that the third parameter of compareAndSwapObject
is expected value, that,由于保证了原子性,A
或 B
线程 首先执行 compareAndSwapObject
将在此处看到 null
,compareAndSwapObject
将实际替换对象 ,而执行 compareAndSwapObject
的下一个线程不会更改该值,因为 实际值不再为 null,而 null 被期望作为对值进行更改的条件。
这里是 putVal
方法的部分代码:
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(); // lazy Initialization
//step1,tabAt(...) is CAS
else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
//step2,casTabAt(...) is CAS
if (casTabAt(tab, i, null,
new Node<K,V>(hash, key, value, null)))
break; // no lock when adding to empty bin
}
...
return null;
}
假设当前有两个线程,A
和B
,当A
执行step1
时,得到true
,但是在同时 B
也执行 step1
并得到 true
。 A
和 B
都执行 step2
。
从这种情况来看,B
的Node
替换了A
的Node
,或者说A
的数据被[替换了=13=], 这是错误的。
不知道对不对,谁能帮我解决一下?
以下是 casTabAt
的实现方式:
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);
}
而 U
声明如下:private static final sun.misc.Unsafe U;
。此 class 的方法保证了低级别的原子性 。从这个用法来看:
casTabAt(tab, i, null, new Node<K,V>(hash, key, value, null))
我们可以看到,assuming that the third parameter of compareAndSwapObject
is expected value, that,由于保证了原子性,A
或 B
线程 首先执行 compareAndSwapObject
将在此处看到 null
,compareAndSwapObject
将实际替换对象 ,而执行 compareAndSwapObject
的下一个线程不会更改该值,因为 实际值不再为 null,而 null 被期望作为对值进行更改的条件。