由单例模式学到:volatile关键字
MSDN上说:
volatile 关键字指示一个字段可以由多个同时执行的线程修改。 声明为 volatile 的字段不受编译器优化的限制。 这样可以确保该字段在任何时间呈现的都是最新的值。
volatile 关键字可应用于以下类型的字段:
-
引用类型。
-
指针类型(在不安全的上下文中)。 请注意,虽然指针本身可以是可变的,但是它指向的对象不能是可变的。 换句话说,您无法声明“指向可变对象的指针”。
-
类型,如 sbyte、byte、short、ushort、int、uint、char、float 和 bool。
-
具有以下基类型之一的枚举类型:byte、sbyte、short、ushort、int 或 uint。
-
已知为引用类型的泛型类型参数。
可变关键字仅可应用于类或结构字段。 不能将局部变量声明为 volatile。
网上看到一篇文章说:
volatile关键字仅应用于类或结构字段,用于通知编译器,将有多个线程访问该字段,因此它不应当对此成员的状态做任何优化,这样可以确保该字段在任何时间呈现的都是最新的值。
不是所有的类型都可以被定义为volatile字段,只有以下类型才可被定义为volatile:
-
引用类型。
-
指针类型(在不安全的上下文中)。
-
整型,如 sbyte、byte、short、ushort、int、uint、char、float 和 bool。
-
具有整数基类型的枚举类型。
-
已知为引用类型的泛型类型参数。
-
IntPtr 和 UIntPtr。
注意观察一下,就能发现只有值或引用的位数不超过本机整型值的位数(在32位系统中,为4个字节)的类型才能成为volatile。为什么会这样呢?我的理解是:编译器之所以保障volatile字段在多线程情况下总是获取到最新值,最重要的一点是volatile字段操作的原子性,即编译后的本地代码只用一条机器指令就能对volatile字段赋值了。如何保证操作的原子性呢?32位系统中,对任何数据操作都是以4字节为基础,自然一条机器指定就能搞定执行一个小于4字节的赋值操作。但如果字段占用内存大于4个字节,那生成赋值语句的机器指令肯定大于一条,这样在多线程的上下文切换中,有可能刚刚赋值到一半,就被切换到其他线程了。这样,便无法保障volatile字段在多线程环境下总是呈现一个完整的、合法的最新值了。
总结:volatile关键字的目的就是在多线程访问该字段时,保证任何时间呈现的都是最新的值!