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

Java并发性:final字段(在构造函数中初始化)是线程安全的吗?

艾仲渊
2023-03-14
问题内容

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

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常见问题解答:

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

这使我感到困惑,因为aMap的设置是aMap = new HashMap<String, String>();。所以其他线程可以看到这些

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

或不 ?


问题答案:

正如已经指出的那样,它是绝对线程安全的,并且final由于其内存可见性影响而在这里很重要。

的存在final保证其他线程将看到在构造函数中,无需任何外部同步完成后,在地图的值。没有final它,不能在所有情况下都得到保证,并且当使新构造的对象可用于其他线程时,您需要使用
安全的发布习惯 ,即(来自Java Concurrency in Practice):

  • 从静态初始化程序初始化对象引用;
  • 将对它的引用存储到volatile字段或AtomicReference中;
  • 将对它的引用存储到适当构造的对象的最终字段中;要么
  • 将对它的引用存储到由锁适当保护的字段中。



 类似资料:
  • 问题内容: 表示变量只能在构造函数中分配一次。 表示它是一个类实例。 我不明白为什么禁止这样做。这些关键字在哪里互相干扰? 问题答案: 每次创建该类的实例时,都会调用一个构造函数。因此,上述代码意味着x的值将在每次创建实例时重新初始化。但是由于变量被声明为final(和static),因此您只能这样做 但是,如果删除静态,则可以执行以下操作: 或这个:

  • 问题内容: 如果未将ArrayList初始化为字段,则将项目添加到ArrayList时出现NullPointerException。谁能解释为什么? 当我将ArrayList初始化为字段时起作用: 当我将ArrayList声明为字段然后在Class构造函数中对其进行初始化时,它不起作用: 问题答案: 因为构造函数中的版本正在创建一个新变量,而该变量恰好与您的成员字段名称相同,而成员字段仍未设置。这

  • 问题内容: 我最近一直在用C#和Java进行编程,并且很好奇初始化我的类字段的最佳位置。 我应该在申报时这样做吗: 还是在构造函数中?: 我真的很好奇你们中的一些资深人士认为这是最佳做法。我要保持一致,并坚持一种方法。 问题答案: 我的规则: 不要在声明中的默认值初始化()。 如果你没有用于更改字段值的构造函数参数,则最好在声明中进行初始化。 如果字段的值由于构造函数参数而改变,则将初始化放入构造

  • 这是一个关于java中子类的非常基本的问题,我还是不明白…… 假设我有一个超类,它有三个字段,并且只有默认的构造函数: 我想添加一个字段x。我无法更改,所以我创建了一个子类: 我现在想从现有的对象生成object: 这样我仍然可以访问,等。 如果不在子类的构造函数中“手动”分配所有这些字段,我如何才能最好地做到这一点?

  • 假设你有这个代码片段 例如,如果编译器决定让它看起来像 这将是一个问题,因为calculateWaitTime()生成一个新线程,该线程可能会将集合视为null或其中没有1。 那么问题又来了,这种重新排序可能吗?或者所有在构造函数之外初始化的最终字段都是在构造函数之前初始化的,或者至少总是由编译器移动到构造函数的顶部

  • 问题内容: 谁能解释以下程序的输出?我认为构造函数要在实例变量之前初始化。因此,我期望输出为“ XZYY”。 问题答案: 正确的初始化顺序是: 如果该类先前尚未初始化,则按文本顺序的静态变量初始化程序和静态初始化块。 构造函数中的super()调用,无论是显式的还是隐式的。 实例变量初始化程序和实例初始化块,按文本顺序。 super()之后构造函数的其余主体。