当前位置: 首页 > 面试题库 >

最终静态变量在Java中线程安全吗?

隆谦
2023-03-14
问题内容

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

我有一堂课,看起来像这样:

    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,此后不进行修改(只读)。

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

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

private static final ConcurrentHashMap<String, HashMap> sharedData;

要么

private static final ConcurrentHashMap<String, ConcurrentHashMap> sharedData;

还是更安全(简单地clone()会更昂贵)?

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

TIA。

(已对静态初始值设定项进行了编辑,以提供更多上下文。)


问题答案:

参考sharedData这是最后的是线程安全的,因为它永远不会改变。Map的内容 不是 线程安全的,因为它最好用Guava
ImmutableMap实现包装,或者java.util.Collections.unmodifiableMap()java.util.concurrent包中使用Map实现之一。

只有当你做 BOTH 将你对地图综合线程安全。任何包含的地图都必须是不可变的,或者也是并发实现之一。

.clone()从根本上被破坏,请远离

默认情况下,克隆是浅表克隆,它将仅返回对容器对象的引用而不是完整副本。关于为什么的一般可用信息中有很好的记录。



 类似资料:
  • 我的问题与静态变量的线程安全有关。 如果两个线程,t1具有静态锁,t2具有对象锁,可以同时继续,那么A类的状态测试将如何是线程安全的呢? 可能是,我错过了一些非常基本的东西,但不确定它是如何工作的。 根据下面的答案,我得到的印象是,如果必须使这些状态成为线程安全的,那么两个锁都应该由正在更新此状态的线程持有,或者确保它被仅静态方法或仅非静态方法访问。对吧?

  • 问题内容: 将变量声明为的区别是什么 要么 如果我只希望变量是局部的,并且是常量(以后不能更改)? 谢谢 问题答案: 仅仅具有预期的效果。 声明static使其成为一个类变量,使其可以使用类名进行访问

  • 问题内容: 通常,最终静态成员,尤其是变量(或静态最终变量,当然可以以任何顺序使用,而不会重叠含义)已广泛用于Java接口中,以定义实现类的 协议行为 ,这意味着实现该类的类(继承)接口必须包含该接口的所有成员。 我无法区分 final 和 final静态 成员。final静态成员是一个声明为final或其他东西的静态成员?在哪些特定情况下应专门使用它们? 永远不能在方法内部,静态方法内部或实例方

  • 问题内容: 假设我有一些Java代码: 如果一个线程正在初始化SomeClass的对象,并且在第二个线程想要再次加载SomeClass的过程中正在初始化静态块中的值,那么该静态块会怎样?即使第一个线程未完成,第二个线程是否仍假设它已初始化而忽略了它?还是发生其他事情? 问题答案: 如果第一个线程尚未完成对SomeClass的初始化,则第二个线程将阻塞。 Java语言规范的12.4.2节中对此进行了

  • 问题内容: 在Java中,何时应使用静态非最终变量? 例如 显然,这里我们不是在谈论常量。 根据我的经验,我经常在使用单例时对它们进行辩护,但后来我最终需要拥有多个实例,这使我感到非常头痛和重构。 似乎很少在实践中使用它们。你怎么看? 问题答案: 统计信息收集可以使用非最终变量,例如,计算创建的实例数。另一方面,对于这种情况,您可能还是要使用etc,这时可能是最终的。另外,如果您要收集多个统计信息

  • 问题内容: 我有一个关于可变范围的问题。 例如: 现在,我创建两个线程,并为每个线程创建一个实例。 当我在每个线程中调用时,可以保证线程安全吗? 本地变量存储在哪里?每个线程的堆栈?堆空间? PS我知道在这种情况下,静态是毫无意义的。我在我们的旧代码中找到了它;我只是想确定我所知道的! 问题答案: 局部变量存储在每个线程自己的堆栈中。这意味着局部变量永远不会在线程之间共享。这也意味着所有本地原始变