最终不可修改的套件是否安全?

时间:2013-11-18 03:15:06

标签: java collections thread-safety

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进行操作...... 所以我的问题是,对于不可修改的集合,当对每个,containssize等使用等操作时,我是否真的需要同步访问?

2 个答案:

答案 0 :(得分:6)

如果它是一个不可修改的Set<String>,根据你的例子,那你很好;因为String对象是不可变的。但是如果它是一组不可变的东西,你必须要小心两个线程都试图改变集合中的同一个对象。

你还必须要注意是否有Set的某个引用,这不是不可修改的。变量可能是不可修改的,但仍然指的是可以通过不同变量修改的Set;但是你的例子似乎已经涵盖了这一点。

答案 1 :(得分:2)

“事实上”不可变的对象是线程安全的。即从未改变其状态的物体。这包括理论上可以改变但永远不会改变的对象。 但是,里面包含的所有对象也必须是“事实上”不可变的。 此外,当您停止修改对象时,该对象才开始变为线程安全。 它需要以安全的方式传递给其他线程。有两种方法可以做到这一点。

1。)只有在停止修改对象后才启动其他线程。在这种情况下,您根本不需要任何同步。

2。)在修改对象时,其他线程已在运行,但是一旦完成对象的构建,就会通过同步机制将其传递给它们。一个ConcurrentLinkedDeque。之后,您不需要任何进一步的同步。