Java 最终的不可修改集是线程安全的吗?
目前还不清楚:不可修改的集合是线程安全的吗?还是应该担心内部状态并发问题Java 最终的不可修改集是线程安全的吗?,java,collections,thread-safety,Java,Collections,Thread Safety,目前还不清楚:不可修改的集合是线程安全的吗?还是应该担心内部状态并发问题 Set<String> originalSet = new HashSet<>(); originalSet.add("Will"); originalSet.add("this"); originalSet.add("be"); originalSet.add("thread"); originalSet.add("safe?"); final Set<String> unmodifi
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?
然后每个线程都会使用如下代码访问它:
synchronized (mySet) {
// Iterate and read operations
}
根据这种逻辑,一次只能有一个线程在集合上操作。。。
所以我的问题是,对于一个不可修改的集合,当使用诸如for each、
contains
、size
等操作时,我真的需要同步访问吗?根据您的示例,如果它是一个不可修改的集合,那么您就可以了;因为String
对象是不可变的。但是,如果它是一组不是不可变的东西,那么必须小心两个线程都试图更改集合中的同一对象
您还必须注意是否有对集合的引用,这不是不可修改的。一个变量可能是不可修改的,但仍然是指可以通过不同变量修改的集合
;但您的示例似乎已经涵盖了这一点。事实上不可变的对象是线程安全的。i、 e.永远不会改变其状态的对象。这包括理论上可以改变但永远不会改变的对象。
但是,其中包含的所有对象也必须是“事实上”不可变的。
此外,当您停止修改对象时,该对象才开始成为线程安全的。
它需要以安全的方式传递给其他线程。有两种方法可以做到这一点
1.)只有在停止修改对象后,才能启动其他线程。在这种情况下,您根本不需要任何同步
2.)在您修改对象时,其他线程已经在运行,但一旦您完成构建对象,您就可以通过同步机制(例如ConcurrentLinkedQue)将其传递给它们。之后,您不需要任何进一步的同步。任何线程都不能修改不可修改的集合,例如,您不能在集合中添加或删除任何内容,但线程可以修改集合元素的状态,这可能需要同步。@LuigImendoza是write,它取决于包含的元素,如果它们是不可变的,则不需要线程同步,例如,在您提供的示例中,集合包含不可变的java.lang.String
s,因此您可以删除同步。是这样吗?在不了解装饰对象实现的情况下,如何确保装饰对象是线程安全的?出于性能或其他一些未预料到的原因,包装集不可能在任意时间修改其内部状态吗?我认为简单的HashSet并非如此,但定制实现可能更复杂。
synchronized (mySet) {
// Iterate and read operations
}