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