javadocs对此不清楚:不可修改的设置线程安全吗?或者我应该担心内部状态并发问题?
Set<String> originalSet = new HashSet<>();
originalSet.add("Will");
originalSet.add("this");
originalSet.add("be");
originalSet.add("thread");
originalSet.add("safe?");
final Set<String> unmodifiableSet = Collections.unmodifiableSet(originalSet);
originalSet = null; // no other references to the originalSet
// Can unmodifiableSet be shared among several threads?
我偶然发现了一段代码,其中一个静态的只读Set
被多个线程共享......原作者写了这样的东西:
mySet = Collections.synchronizedSet(Collections.unmodifiableSet(originalSet));
然后每个线程都使用以下代码访问它:
synchronized (mySet) {
// Iterate and read operations
}
通过这个逻辑,只有一个线程可以立即对Set进行操作......
所以我的问题是,对于不可修改的集合,当对每个,contains
,size
等使用等操作时,我是否真的需要同步访问?
答案 0 :(得分:6)
如果它是一个不可修改的Set<String>
,根据你的例子,那你很好;因为String
对象是不可变的。但是如果它是一组不可变的东西,你必须要小心两个线程都试图改变集合中的同一个对象。
你还必须要注意是否有Set
的某个引用,这不是不可修改的。变量可能是不可修改的,但仍然指的是可以通过不同变量修改的Set
;但是你的例子似乎已经涵盖了这一点。
答案 1 :(得分:2)
“事实上”不可变的对象是线程安全的。即从未改变其状态的物体。这包括理论上可以改变但永远不会改变的对象。 但是,里面包含的所有对象也必须是“事实上”不可变的。 此外,当您停止修改对象时,该对象才开始变为线程安全。 它需要以安全的方式传递给其他线程。有两种方法可以做到这一点。
1。)只有在停止修改对象后才启动其他线程。在这种情况下,您根本不需要任何同步。
2。)在修改对象时,其他线程已在运行,但是一旦完成对象的构建,就会通过同步机制将其传递给它们。一个ConcurrentLinkedDeque。之后,您不需要任何进一步的同步。