Java 并发:final 字段(在构造函数中初始化)是线程安全的吗? [英] Java concurrency: is final field (initialized in constructor) thread-safe?

查看:21
本文介绍了Java 并发:final 字段(在构造函数中初始化)是线程安全的吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

谁能告诉我这个类是否是线程安全的?

Can anyone tell me whether this class is threadsafe or not ?

class Foo {

    private final Map<String,String> aMap;

    public Foo() {
        aMap = new HashMap<String, String>();
        aMap.put("1", "a");
        aMap.put("2", "b");
        aMap.put("3", "c");
    }

    public String get(String key) {
        return aMap.get(key);
    }

}

不澄清问题是我的错.根据 JMM 常见问题:

It my fault to not clarify the question. According to JMM FAQ :

应该提供初始化安全的新保证.如果一个对象被正确构造(这意味着对它的引用在构造过程中不会转义),那么所有看到对该对象的引用的线程也将看到在构造函数中设置的其最终字段的值,而无需同步.

A new guarantee of initialization safety should be provided. If an object is properly constructed (which means that references to it do not escape during construction), then all threads which see a reference to that object will also see the values for its final fields that were set in the constructor, without the need for synchronization.

这让我感到困惑,aMap 的集合是 aMap = new HashMap();.所以其他线程可以看到这些

This made me confuse that the set to aMap is aMap = new HashMap<String, String>();. So other threads can see these

aMap.put("1", "a");
aMap.put("2", "b");
aMap.put("3", "c");

要不要?

我发现了这个问题 完全解决了我的问题

I found this question that exactly closed to my question

推荐答案

正如已经指出的那样,它绝对是线程安全的,并且 final 在这里很重要,因为它具有内存可见性效果.

As already pointed out it's absolutely thread-safe, and final is important here due to its memory visibility effects.

final 的存在保证其他线程在构造函数完成后可以在没有任何外部同步的情况下看到映射中的值.没有 final 就不能保证在所有情况下都可以,并且在使新构造的对象可用于其他线程时,您将需要使用 安全发布习惯用法,即(来自 Java 并发实践):

Presence of final guarantees that other threads would see values in the map after constructor finished without any external synchronization. Without final it cannot be guaranteed in all cases, and you would need to use safe publication idioms when making newly constructed object available to other threads, namely (from Java Concurrency in Practice):

  • 从静态初始化器初始化对象引用;
  • 将对其的引用存储到可变字段或 AtomicReference 中;
  • 将对其的引用存储到正确构造的对象的最终字段中;或
  • 将对其的引用存储到由锁适当保护的字段中.

这篇关于Java 并发:final 字段(在构造函数中初始化)是线程安全的吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆