Java 由于内存不一致,线程能否观察到对象中的垃圾值?

Java 由于内存不一致,线程能否观察到对象中的垃圾值?,java,memory-model,Java,Memory Model,经过大量的研究,我相信我对JMM非常了解,当然也非常了解,当一个对象在两个线程之间共享时,必须在同一个监视器上同步所有访问。我知道,如果多个活动线程同时访问一个对象,那么所有关于它们将观察到什么的赌注都将被取消 但是,如果一个对象是在使用它的其他线程启动之前(或者甚至是在该线程被构造之前)确定并实际构造的,那么JMM是否保证后一个线程看到的对象的内容与前一个设置线程配置的内容相同 在线程中,是否有可能第一次引用一个对象并观察到脏内存(例如CPU缓存),而不是对象的真实内容?或者JMM是否保证当第

经过大量的研究,我相信我对JMM非常了解,当然也非常了解,当一个对象在两个线程之间共享时,必须在同一个监视器上同步所有访问。我知道,如果多个活动线程同时访问一个对象,那么所有关于它们将观察到什么的赌注都将被取消

但是,如果一个对象是在使用它的其他线程启动之前(或者甚至是在该线程被构造之前)确定并实际构造的,那么JMM是否保证后一个线程看到的对象的内容与前一个设置线程配置的内容相同

在线程中,是否有可能第一次引用一个对象并观察到脏内存(例如CPU缓存),而不是对象的真实内容?或者JMM是否保证当第一次获得对任何给定对象的引用时,它引用的内存是一致的

我这样问是因为我在很多地方使用了一种特定的模式,但我仍然不确定。通常我有一个对象,它是以一种零碎的方式构造和配置的,然后不可更改地使用。因为它是一顿一顿地配置的,所以它的任何成员都不能是最终成员(除非我必须这样做,否则我不想将它们全部更改为构建器模式)

例如,创建HTTP连接处理程序,并添加插件对象以处理特定的HTTP请求。处理程序是使用mutators创建和配置的,然后安装到TCP连接处理器中,该处理器使用线程池来处理连接。由于连接处理程序是在连接处理器的线程池启动之前配置和安装的,并且在安装到连接处理器后从未更改,因此我不会在设置所有内容的线程和处理连接的线程之间使用显式同步

在这种特定情况下,配置线程的线程很可能也是启动线程池的同一个线程,而且由于线程池的启动是同步的,因此所有用完它的线程也在同一个线程池对象上同步,因此这可能会掩盖任何潜在问题(我的API不要求启动线程与配置线程相同)。

通常,当线程交互时,您应该具有before关系。例如,由并发队列提供。不一定需要更精细的同步

在线程之间传递对象而不在关系之前发生的罕见情况称为不安全发布。
final
字段的使用有一些规则,可以确保安全。但是,您应该很少发现自己希望依赖于此


在线程上调用
start
和线程的执行之间始终存在“发生在前”的关系。因此,如果在启动之前将对象安全发布到启动线程,则启动线程也会一致地看到对象。

不标记变量“volatile”以防止线程看到“dirty”值当然,根据定义,安全地将A发布到B必须包括具有构造和配置A的同一线程,该线程还构造了引用A的B。