在Java程序员中,众所周知,为了使双重检查锁定正常工作,变量必须声明为
volatile
,并且同步对象的初始化是不够的。这种意识可能主要是因为volatile
关键字的语义在1.5中被改变以包括“发生在”关系,至少部分上是为了使双重检查锁定安全;据我所知,“发生在”关系意味着写入volatile
变量会导致线程中所有缓存变量被写入主内存,并且在从volatile
变量读取后,所有缓存变量都被认为是过时的,必须从主内存重新读取,以便在写入volatile
变量之前写入的所有内容都保证在稍后从该变量读取之前“发生”。
Stack Overflow 似乎认为,对于C#,volatile
在双重检查锁定中是不必要的(尽管注意到这可能特定于某些CPU或Microsoft的实现),同时也认为Java的synchronized
语句的语义与C#的lock
语句完全相同,这表明在Java中发现的相同问题也将存在于C#中,除非两种语言之间的双重检查锁定的语义存在其他主要差异。
那么...哪一个是正确的?C#中的双重检查锁定是否比Java更安全?如果是,有什么语言语义的差异使得情况如此?
如果不是,没有volatile
会出现什么具体问题?C#中volatile
的语义是否建立了类似Java的“先行发生”关系,因此使用volatile
的C#中的双重检查锁定与Java 1.5之后一样安全?