java - Java中的最终静态变量是线程安全的吗?

标签 java multithreading static hashmap final

我已经阅读了很多,但还没有找到明确的答案。

我有一个如下所示的类(class):

    public class Foo() {

        private static final HashMap<String, HashMap> sharedData;

        private final HashMap myRefOfInnerHashMap;

        static {
           // time-consuming initialization of sharedData
           final HashMap<String, String> innerMap = new HashMap<String, String>;
           innerMap.put...
           innerMap.put...
           ...a

           sharedData.put(someKey, java.util.Collections.unmodifiableMap(innerMap));
        }

        public Foo(String key) {
            this.myRefOfInnerHashMap = sharedData.get(key);
        }

        public void doSomethingUseful() {
            // iterate over copy
            for (Map.Entry<String, String> entry : this.myRefOfInnerHashMap.entrySet()) {
                ...
            }
        }
     }

我想知道从 Foo 的实例访问 sharedData 是否是线程安全的(如构造函数和 doSomethingUseful() 中所示)。 Foo 的许多实例将在多线程环境中创建。

我的意图是 sharedData 在静态初始化器中初始化,之后不再修改(只读)。

我读到的是不可变对象(immutable对象)本质上是线程安全的。但我只在似乎是实例变量的上下文中看到了这一点。不可变的静态变量是线程安全的吗?

我发现的另一个构造是 ConcurrentHashMap。我可以制作 ConcurrentHashMap 类型的 sharedData,但它包含的 HashMaps 也必须是 ConcurrentHashMap 类型吗?基本上..

private static final ConcurrentHashMap<String, HashMap> sharedData;

private static final ConcurrentHashMap<String, ConcurrentHashMap> sharedData;

或者它会更安全(但简单地克隆()成本更高)?

this.myCopyOfData = sharedData.get(key).clone();

TIA。

(静态初始化器已被编辑以提供更多上下文。)

最佳答案

sharedDatareference 是 final 的,它是线程安全的,因为它永远无法更改。 Map 的内容是 NOT 线程安全的,因为它需要最好用 Guava ImmutableMap 实现或 java.util.Collections.unmodifiableMap()< 包装 或使用 java.util.concurrent 包中的 Map 实现之一。

只有BOTH你才能在 map 上获得全面的线程安全。任何包含的 Map 都必须是不可变的,或者也是并发实现之一。

.clone() 根本坏掉了,远离

默认情况下克隆是浅克隆,它只会返回对容器对象的引用而不是完整的副本。在普遍可用的信息中详细记录了原因。

关于java - Java中的最终静态变量是线程安全的吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2412124/

相关文章:

java - 为什么是 Libgdx Gdx.gl10.glLineWidth(width);不对更改投影属性使用react

java - 如何从 GMaven 脚本中加载/查找 JAR 资源?

java - 如何用Java编写原子函数?

C# Task Parallel Library 第一次慢

java - java 1.8 接口(interface)中添加静态方法

java - 使用 freemarker 生成要在电子邮件中发送的 html,他们是否无论如何都要使用渲染的 jsp 页面?

java - 使用散列法查找总长度最小的字符串子数组,该子数组包含原始数组中的所有不同字符串

python - `Pool.*_async` 功能从未准备好

c# - 为什么设置静态方法会导致堆栈溢出?

c++ - 访问静态和非静态的模板构造函数和函数