Java 垃圾收集和同步可见性
我读到过关于将对象标记为volatile并不能保证其成员的可见性的文章(我不是说线程安全,只是说内存可见性,引用: JVM只会认为对象引用是不稳定的,而不会认为对象数据本身是驻留在堆上的 我的问题是:Java 垃圾收集和同步可见性,java,multithreading,synchronized,volatile,Java,Multithreading,Synchronized,Volatile,我读到过关于将对象标记为volatile并不能保证其成员的可见性的文章(我不是说线程安全,只是说内存可见性,引用: JVM只会认为对象引用是不稳定的,而不会认为对象数据本身是驻留在堆上的 我的问题是: 同步将确保成员(在同一个锁对象上)在被编辑的情况下的可见性。这是因为在锁结束(释放)之前发生的操作使其他线程可见吗 如果在对象上使用volatile,并且对象引用发生更改。如果旧引用缓存在一个线程CPU缓存中,会发生什么情况?GC会使其保持活动状态吗 示例代码: class Test{ vol
class Test{
volatile Data data;
}
Class Data{
int x;
int y;
}
data= new Data(); // happens-before relationship only on creation
//writer
Thread writerThread = new Thread(() -> {
data.setX(a);
data.setY(b);
});
//reader
Thread readerThread = new Thread(() -> {
// read here is not guaranteed visibility, x,y not volatile
int x = data.getX();
int y = data.getY();
});
发生在
之前关系将保证这一点。而关键字也会在写入线程和读取线程之间构建发生在
之前的关系是的,volatile之前发生过,但在本例中仅发生在引用上。这就是成员不具有可见性的原因,对吗?@MohammadKarmi
之前发生过
不与任何引用绑定。如果threadA发生在threadB之前,则表示threadB可以看到任何变量,就像threadA一样。我理解。我已经编辑了post带有示例代码。在这种情况下,您无法保证x,y的可见性。因为在更改对象引用数据
而不是x,y时,将执行之前发生的操作。因此,如果在对象创建数据后对其进行编辑,则x,y不会是最新的。对吗?@MohammadKarmi是的…我认为这更多地是关于原子
读卡器线程先引用data
,然后访问x
和y
。这些动作不是原子的,所以volatile不能保证x
和y
的可见性。只有在syncronized
块中访问data
和x
时,synchronized关键字才能做到这一点。我已经编辑了我用完整的代码进一步解释了这篇文章,这个可见性不是原子的吗?因为一个线程读取另一个线程写入。当读取x,y时,我无法从内存中获取它们,它们可能是缓存的,而不是最新的。关于你的第二个问题,标记为volatile的对象与任何其他对象一样被收集。@DavidSoroko这不是我的意思。我表示如果对象被缓存到其他线程,但它的引用被其他线程更改。是否应将其标记为删除?对象是可访问的还是不可访问的。如果不可访问,GC将堆内存“标记”为可用,并将其“扫掠”到可用内存列表中。