java - 并发HashMap有一个 volatile 表,为什么在get()时需要unsafe.getObjectVolatile()

标签 java

如标题;我认为当不需要get()时unsafe.getObjectVolatile(),并且 volatile 表可以确保线程获取最新的元素

transient volatile Node<K,V>[] table;


public V get(Object key) {
    Node<K,V>[] tab; Node<K,V> e, p; int n, eh; K ek;
    int h = spread(key.hashCode());
    if ((tab = table) != null && (n = tab.length) > 0 &&
        (e = tabAt(tab, (n - 1) & h)) != null) {
        if ((eh = e.hash) == h) {
            if ((ek = e.key) == key || (ek != null && key.equals(ek)))
                return e.val;
        }
        else if (eh < 0)
            return (p = e.find(h, key)) != null ? p.val : null;
        while ((e = e.next) != null) {
            if (e.hash == h &&
                ((ek = e.key) == key || (ek != null && key.equals(ek))))
                return e.val;
        }
    }
    return null;
}


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);
}

最佳答案

有两个原因:

  1. 代码没有通过字段 table 访问 table 的值 - 相反,引用被复制到名为 tab 的本地变量并通过该变量访问。由于该变量不是 volatile (并且局部变量不能是 volatile 的),因此不会授予任何内存模型保证。
  2. volatile 的保证仅在一个线程 A 写入 volatile 变量时才适用;从同一个 volatile 变量读取的其他线程保证可以看到线程 A 所做的所有更改。但是,在这种情况下,变量 table 不会频繁更新 - 相反,数组的元素会更新为更新了哪些table点。但这些元素不是 volatile ——事实上,Java 不支持 volatile 数组元素。但是,使用 Unsafe.getObjectVolatileUnsafe.putObjectVolatile,当您无法在 Java 中直接声明 volatile 元素数组时,您可以使用 volatile 语义来访问数组元素。这就是这段代码所需要的。

关于java - 并发HashMap有一个 volatile 表,为什么在get()时需要unsafe.getObjectVolatile(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59908363/

相关文章:

java - 我无法将其与 Jpanel 的右侧部分对齐

java - 监听器和计时器之间的通信

java - 将 MAC 地址字节数组格式化为字符串

java - 在 maven 插件中设置 tomcat 7 系统属性

java - 将 GZIP 压缩与 Spring Boot/MVC/JavaConfig 与 RESTful 结合使用

Java:项目中的两个 jar 具有相同的类。

java - -XX :+HeapDumpOnOutOfMemoryError not creating hprof file in OOM

java - Android SQLite : How to ensure consistency in batch upload and delete upon success if no unique key is given?

java - 如何在 Java 8 中为匿名类启用 Android Studio/IDEA 闭包折叠?

java - 连接到 .accdb 文件时为 "Given file does not exist"