挥发是不必要的。好吧,**
volatile用于在变量的读写之间创建内存屏障。
lock使用时,
lock除了将对块的访问限制在一个线程之外,还会在内的块周围创建内存屏障。
内存屏障使之成为可能,因此每个线程都读取变量的最新值(而不是某些寄存器中缓存的本地值),并且编译器不会对语句进行重新排序。
volatile不需要使用*,因为您已经锁定了。
约瑟夫·阿尔巴哈里(Joseph
Albahari)以前所未有的方式解释了这种东西。
并且一定要查看Jon Skeet的C#实现单例指南。
update :
*
volatile导致对变量的读取为
VolatileReads ,对变量的写入为
VolatileWrites,这在x86和CLR上的x64上使用来实现
MemoryBarrier。在其他系统上,它们可能更细粒度。
**仅当您在x86和x64处理器上使用CLR时,我的回答才是正确的。在其他内存模型中,例如在Mono(和其他实现),Itanium64和将来的硬件上,
可能 是正确的。这就是乔恩在“陷阱”中的文章中针对双重检查锁定所指的内容。
为了使代码在内存模型较弱的情况下正常工作,可能需要执行以下操作之一(将变量标记为
volatile,使用进行读取
Thread.VolatileRead或插入对的调用)
Thread.MemoryBarrier。
据我了解,在CLR(即使是在IA64上),写入也不会重新排序(写入始终具有发布语义)。但是,在IA64上,除非将其标记为易失性,否则可能会将读取重新排序为先于写入。不幸的是,我无权使用IA64硬件,因此我所说的只是猜测。
我还发现这些文章有所帮助:
http://www.preproject.com/KB/tips/MemoryBarrier.aspx
万斯莫里森的文章(一切链接到这一点,它谈论的双重检查锁定)
克里斯brumme的文章
(所有链接到本)
乔·达菲(Joe Duffy):双重检查锁定的残破变体
luis abreu的有关多线程的系列也很好地概述了这些概念
http://msmvps.com/blogs/luisabreu/archive/2009/06/29/multithreading-load-and-
store-reordering.aspx
http:// msmvps。 com / blogs / luisabreu / archive / 2009/07/03 /
multithreading-introducing-memory-
fences.aspx



