从单例模式看C#的volatile关键字

目录

  1. Singleton示例

  2. volatile解决问题1:CPU缓存

  3. volatile解决问题2:编译器优化(指令乱序)

一. 标准的单例模式示例

public sealed class Singleton
{
    // 静态实例
    private static volatile Singleton instance = null;
    // Lock对象,线程安全所用
    private static object syncRoot = new Object();

    private Singleton() { }

    public static Singleton Instance
    {
        get
        {
            if (instance == null)                            //一次比较
            {
                lock (syncRoot)
                {
                    if (instance == null)                    //二次比较
                        instance = new Singleton();
                }
            }
            return instance;
        }
    }
}

注意静态示例自动前的修饰符: volatile,为什么必须指定volatile, 如果不使用该关键字,会有什么后果呢。

volatile【易变的】,查msdn:
volatile 关键字指示一个字段可以由多同时执行的线程修改。 声明为 volatile 的字段不受编译器优化(假定由单个线程访问)的限制。 这样可以确保该字段在任何时间呈现的都是最新的值。

那在底层到底发生了什么,难道不使用volatile,指令执行时,字段的值还不是新的吗,这得从计算机架构及编译器优化两个方面说起。

二. CPU缓存问题

采用volatile关键字,每次读字段值时,都必须从内存中获取,也就是说,对该字段禁用CPU缓存。

由于现代的CPU都存在多个核心,每个核心有独立的内部缓存,而对象字段最初是保存在内存中的,执行指令前,会首先检查缓存中是否存在该字段,如果没有,从内存中读取数据到CPU缓存,进行运算, 如果缓存存在,则无需访问内存,直接使用缓存的数据。

针对单例模式示例,两个线程分别在两个CPU核心运行,两个核心同时运行到上面语句“第一次比较”,instance字段都保存在各个CPU的内部缓存中,通过lock关键字,两个线程会串行执行lock语句块。

比如核心A已经运行完成lock语句块,内存中的instance已经更新,此时核心B继续运行,由于核心B已经缓存了instance示例,在二次比较时,还是认为instance字段为空,这样就导致 new Singleton()执行了两次。

三. 编译器优化问题

采用volatile关键字, 可以避免指令重新排序(instruction reordering), 例如,考虑如下一个循环:

while(true)
{
   if(myField)
   {
      //do something
   }
}

如果myField字段没有指定volatile, 在JIT编译时,出于性能优化考虑,编译器会以如下方式重新排序指令:


if(myField)
{
   while(true)
   {
      //do something
   }
}

这种情况下,如果你在另一个线程中修改字段myFiled, 运行结果将完成不同。
通常情况下,推荐使用lock语句(Monitor.Enter /Monitor.Exit),但如果你在这个语句块内仅仅修改了一个字段,volatile将有更好的性能表现。

转载于:https://www.cnblogs.com/iyxqj/p/3839672.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值