在Java中进行双重检查锁定是否需要`volatile`而不是C#?

The*_*ock 5 c# java volatile double-checked-locking

在Java程序员中众所周知,为了使双重检查锁定正常运行,必须声明变量volatile,并且同步对象的初始化是不够的.

意识可能主要是因为volatile关键字的语义在1.5中改变为包括"之前发生"关系,至少部分是为了使双重检查锁定安全; 根据我的理解,"发生在之前"关系意味着写入volatile变量会导致线程中的所有缓存变量被写入主内存,并且在从volatile变量读取后,所有缓存变量都被认为是陈旧的,并且必须是从主内存重新读取,以便在写入volatile变量之前写入的所有内容都保证在"稍后从该变量读取之前"发生.

Stack Overflow 似乎认为,对于C#来说,volatile双重检查锁定是不必要的(尽管有人担心这可能是特定于某些CPU或微软的实现),同时也认为Java synchronized语句的语义与 C#的语义完全相同lock声明,这表明在C#中也存在Java中发现的相同问题,除非在两种语言之间的双重检查锁定的语义中存在一些其他主要差异.

那么......哪个是正确的?C#中的双重检查锁定实际上比Java更危险吗?如果是这样,那么语言语义有何不同呢?

如果不是,没有具体可能出错的是volatile什么?volatileC#中的语义是否像Java一样建立了"发生在之前"的关系,因此双重检查锁定在C#中是安全的,volatile因为它在Java中是1.5?

Gus*_*man 3

来自MSDN:“ 易失性关键字表示一个字段可能会被同时执行的多个线程修改。声明为易失性的字段不受假定由单个线程访问的编译器优化的影响。这确保了最多- 现场始终存在最新值。”

因此,仅当您从多个线程更改变量的值时,易失性才有用。如果您对使用相同锁定对象访问共享资源的代码区域进行 lock() 操作,则可以保证只有一个线程可以同时访问这些代码区域,那么除非您要修改锁定对象(这是一个非常糟糕的主意),否则不需要 volatile 。