如果Collection线程只在构造函数中编写,那么它是否安全?

时间:2014-06-17 12:13:43

标签: java concurrency

假设我们有这个班级

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. 执行构造函数后,集合只会读取而不会被修改。
  4. 如果没有,是否有一个纯Java替代Guava的不可变集合?

4 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:1)

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

但无论对象是如何创建并可用的,都可以保证线程安全。

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 :(得分:0)

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

此外,当您在示例中添加字符串,并且字符串本身在java中是不可变的时,如果添加了可变对象然后决定从不同的线程修改/读取它们,则会遇到麻烦(在此需要同步块)案件)。

答案 3 :(得分:0)

提供线程安全

1)构造函数在完全构造之前不会泄漏引用。

2)没有人有办法访问该系列。

3)不能创建可以编辑集合的子类。

作为一般规则,如果你想实现这个使用来自guava的不可变集合,那么这个行为对程序员来说是显而易见的,然后返回整个映射是安全的。我认为在纯java中你可以返回一个不可修改的集合视图。