我发现关于可见性的所有例子都是基本类型的例子。我想知道的是:如果一个对象在堆中新建,当一个线程调用其方法来改变其状态时,没有锁定或同步,其他线程会看到这个变化? 想象一下Java.Colletion对象,一个线程调用它的add()方法
有人说堆中的对象仍然存在可见性问题,但JLS说: 17.4.1共享变量 可以在线程之间共享的内存称为共享内存或堆内存。
和 http://www.artima.com/insidejvm/ed2/jvm2.html说: 线程的Java堆栈存储线程的Java(非本机)方法调用的状态。 Java方法调用的状态包括其局部变量,调用它的参数,返回值(如果有)和中间计算。
所以我认为,JVM不会将堆中的对象复制到CPU缓存中。如果这是正确的,那么堆中的对象将不会出现可见性问题,因为线程只引用堆中的对象。
顺便说一句 假设一个线程调用.add()时会出现并发问题。在正常过程中,更改必须使用锁定保护,因此这个问题不是问题。但我只是想知道:)
答案 0 :(得分:3)
答案是“不,其他线程不会必然看到对集合的更改”,因为(大多数)标准集合不是线程安全的 - 也就是说,它们不是安全地公布他们的国家。 (另一个主题可能会或可能看不到变化)。
这就是创建java.util.concurrent package的原因 - 它提供了java.util.Collections的线程安全实现。
答案 1 :(得分:2)
如果您有synchronized
,原子变量或其他提供发生在语义之前的并发容器,您仍然可以在没有volatile
的情况下执行内存同步。但是,如果你不做这些事情,那么在内存可见性方面没有任何保证。
在您的特定情况下,如果您想在一个线程中的容器上调用add()
并且在没有显式锁定的情况下在另一个线程中看到它,那么这仅在容器是并发容器时才有效(例如, java.util.concurrent
包中的其中一个)或同步的(例如Collections.synchronizedList
)。