关于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;
}  

假设当前有两个线程,AB,当A执行step1时,得到true,但是在同时 B 也执行 step1 并得到 trueAB 都执行 step2

从这种情况来看,BNode替换了ANode,或者说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,由于保证了原子性,AB 线程 首先执行 compareAndSwapObject 将在此处看到 nullcompareAndSwapObject 将实际替换对象 ,而执行 compareAndSwapObject 的下一个线程不会更改该值,因为 实际值不再为 null,而 null 被期望作为对值进行更改的条件