如果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
是否是线程安全的
- 对集合的引用是
private
和final
。没有人可以直接访问该集合李> - 唯一的写访问发生在构造函数中
- 构造函数执行后,集合将只读取而不修改李>
如果没有,是否有纯Java替代Guava的不可变集合
# 1 楼答案
这取决于如何发布对此对象的访问。虽然}是最终的,因此保证对所有线程都可见,但不保证在构造函数结束之前发生映射的填充
bar
{然而,无论对象是如何创建和提供的,这都将保证线程安全
Testing initialization safety of final fields
https://stackoverflow.com/a/23995782/676877
# 2 楼答案
只要以只读方式访问,我认为您应该是安全的。此外,java提供了通过collections类上的静态方法公开的基础集合的不可变版本,因此我将介绍
Collections.unmodifiableSet()
另外,当您在示例中添加字符串,并且字符串本身在java中是不可变的时,如果您添加可变对象,然后决定从不同线程修改/读取它们,您将遇到麻烦(在这种情况下,您需要同步块)
# 3 楼答案
你的
Foo
和bar
实际上是不可变的。它是线程安全的# 4 楼答案
它是线程安全的,前提是
1)构造器在完全构造之前不会泄漏引用
2)任何人都无法访问该集合
3)无法创建可编辑集合的子类
但是,作为一般规则,如果您想要实现此功能,请使用来自guava的不可变集合,这将使行为对程序员来说是明确的,然后可以安全地返回整个映射。我认为在纯java中,可以返回集合的不可修改视图