java - 关于ConcurrentHashMap的putVal方法源代码的一个困惑

标签 java multithreading concurrenthashmap

以下是 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

enter image description here

从这种情况来看,BNode取代了ANode,或者说A的数据被B替换,这是错误的。

不知道是对还是错,谁能帮我解决一下吗?

最佳答案

以下是 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;。此类的方法在低级别保证原子性。从这个用法来看:

casTabAt(tab, i, null, new Node<K,V>(hash, key, value, null))

我们可以看到,assuming that the third parameter of compareAndSwapObject is expected value, that ,由于保证了原子性,首先执行 compareAndSwapObjectAB 线程将看到 null 这里和 compareAndSwapObject 实际上会替换对象,而下一个执行 compareAndSwapObject 的线程不会更改该值,因为 实际值不再为 null,而 null 被期望作为对值进行更改的条件

关于java - 关于ConcurrentHashMap的putVal方法源代码的一个困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53536957/

相关文章:

multithreading - Visual C++ (CLI) 线程

javascript - 限制 Web Worker CPU 利用率?

ios - 在不同线程上调用的类的实例方法可以使用类的属性吗?

java - 提高非重复并发 ArrayList 的性能

java - 在这个例子中使用ConcurrentMap.replace有什么意义

java - 使用 "Real-Time Feeling"将行添加到 JTable

java - 无法通过 '11.0.4'确定Java版本

执行 Java 代码即可在 O(1) 内获得结果

java - 当我尝试检测具有相同名字和姓氏的人时,我的 ArrayList 有什么问题。我正在使用正则表达式模式

Java SimpleDateFormat 无法正确解析(我使用正确的大写/小写字母..)