在 Java 程序员中众所周知,为了使双重检查锁定正确运行,必须将变量声明为 volatile
,并且同步对象的初始化是不够的。
这种意识可能主要是因为 volatile
关键字的语义在 1.5 中被更改为包含“发生在之前”的关系,至少部分是为了使双重检查锁定安全;据我了解,“先发生”关系意味着写入 volatile 变量会导致线程中的所有缓存变量都写入主内存,并且在从 volatile 变量读取后,所有缓存变量都被认为是陈旧的,并且必须从主内存中重新读取,以便在写入 volatile 变量之前写入的所有内容都保证“发生在”稍后从该变量读取之前。
堆栈溢出 seems to believe对于 C#,volatile
对于双重检查锁定来说是不必要的(尽管注意到这可能特定于某些 CPU 或 Microsoft 的实现),同时也相信 Java 的 synchronized 语义
语句是 exactly the same作为 C# 的 lock
语句,这表明在 Java 中发现的相同问题也将存在于 C# 中,除非两种语言之间双重检查锁定的语义存在其他一些主要差异。
那么……哪个是正确的? C# 中的双重检查锁定实际上没有 Java 中的危险吗?如果是这样,是什么语言语义不同使情况如此?
如果不是,如果没有 volatile
,具体会出现什么问题? C# 中 volatile
的语义是否像 Java 一样建立了“发生之前”的关系,因此双重检查锁定在 C# 中与 volatile
一样安全,就像在 Java 中一样从 1.5 开始?
最佳答案
来自 MSDN :“volatile 关键字表示一个字段可能会被同时执行的多个线程修改。声明为 volatile 的字段不受假设由单个线程访问的编译器优化的影响。这确保了最新的-日期值始终存在于字段中。”
因此,volatile 仅在您从多个线程更改变量值时才有用。如果你 lock() 使用同一个锁定对象访问共享资源的代码区域,你保证只有一个线程可以同时访问这些代码区域,那么除非你正在修改锁定对象(这是一个非常糟糕的主意),否则不需要 volatile .
关于c# - Java 中的双重检查锁定是否需要 `volatile` 而不是 C#?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23072422/