在此代码中易失性是多余的吗?
public class Test {
private volatile Map<String, String> map = null;
public void resetMap() { map = new ConcurrentHashMap<>(); }
public Map<String, String> getMap() { return map; }
}换句话说,map = new ConcurrentHashMap<>();是否提供了任何可见性保证?
据我所见,ConcurrentMap提供的唯一保证是:
在将对象作为键或值放置到ConcurrentMap之前,线程中的操作发生在访问或删除另一个线程中的ConcurrentMap之后的操作之前。
java.util.concurrent (CopyOnWriteArrayList等)中的其他线程安全集合如何?
发布于 2012-08-29 11:46:07
volatile并不是多余的,因为您正在更改对映射的引用。也就是说,ConcurrentMap只提供有关集合内容的监护人,而不提供对它的引用。
另一种选择是
public class Test {
private final Map<String, String> map = new ConcurrentHashMap<>();
public void resetMap() { map.clear(); }
public Map<String, String> getMap() { return map; }
}java.util.concurrent (CopyOnWriteArrayList等)中的其他线程安全集合如何?
只有集合的行为才是线程安全的。对集合的引用不是线程安全的,集合中的元素通过将它们添加到集合中而不是线程安全。
发布于 2012-08-29 11:47:53
volatile在这里是必要的。它适用于引用,而不适用于它所引用的内容。换句话说,一个对象是否是线程安全并不重要,其他线程不会看到map字段的新值(例如,可能会看到以前引用的并发映射或null)。
此外,即使您的对象是不可变的(例如String),您仍然需要volatile,更不用说其他线程安全的集合了,比如CopyOnWriteArrayList。
发布于 2012-08-29 11:52:45
这不仅仅是参考资料的问题。通常,如果没有volatile修饰符,其他线程可能会观察到对对象的新引用,但会观察到对象处于部分构造的状态。一般来说,即使在查阅了文档之后,也不容易知道哪些对象是安全的,可以通过数据竞赛发布。一个有趣的注意是,JLS确实为线程安全的不可变对象保证了这一点,所以如果文档提到这两个属性,那就足够了。
ConcurrentHashMap显然不是一个不可变的对象,所以这不适用,而且文档没有提到任何有关数据竞争发布的内容。通过对源代码的仔细检查,我们可以得出结论,它确实是安全的,但是,如果没有明确的文档记录,我不建议依赖这样的发现。
https://stackoverflow.com/questions/12177081
复制相似问题