有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

如果java只在构造函数中编写,它是线程安全的集合吗?

假设我们有这门课

final class Foo {
    private final Set<String> bar = new HashSet<>();

    public Foo() {
        bar.add("one");
        bar.add("two");
        bar.add("three");
    }

    public boolean contains(final String s) {
        return bar.contains(s);
    }
}

实例化Foo并从多个线程调用该对象的contains是否是线程安全的

  1. 对集合的引用是privatefinal。没有人可以直接访问该集合
  2. 唯一的写访问发生在构造函数中
  3. 构造函数执行后,集合将只读取而不修改

如果没有,是否有纯Java替代Guava的不可变集合


共 (4) 个答案

  1. # 1 楼答案

    这取决于如何发布对此对象的访问。虽然bar{}是最终的,因此保证对所有线程都可见,但不保证在构造函数结束之前发生映射的填充

    然而,无论对象是如何创建和提供的,这都将保证线程安全

    private final Set<String> bar;
    
    public Foo() {
        bar = new HashSet<String>(Arrays.asList("one", "two", "three"));
    }
    

    Testing initialization safety of final fields

    https://stackoverflow.com/a/23995782/676877

  2. # 2 楼答案

    只要以只读方式访问,我认为您应该是安全的。此外,java提供了通过collections类上的静态方法公开的基础集合的不可变版本,因此我将介绍Collections.unmodifiableSet()

    另外,当您在示例中添加字符串,并且字符串本身在java中是不可变的时,如果您添加可变对象,然后决定从不同线程修改/读取它们,您将遇到麻烦(在这种情况下,您需要同步块)

  3. # 3 楼答案

    你的Foobar实际上是不可变的。它是线程安全的

  4. # 4 楼答案

    它是线程安全的,前提是

    1)构造器在完全构造之前不会泄漏引用

    2)任何人都无法访问该集合

    3)无法创建可编辑集合的子类

    但是,作为一般规则,如果您想要实现此功能,请使用来自guava的不可变集合,这将使行为对程序员来说是明确的,然后可以安全地返回整个映射。我认为在纯java中,可以返回集合的不可修改视图