https://blog.csdn.net/az44yao/article/details/102792359

31 篇文章 0 订阅

原创链接:https://blog.csdn.net/az44yao/article/details/102792359

线程安全的单例模式常见写法是双重检查加锁。代码如下:

class Singleton {
    private volatile static Singleton singleton;
 
    private Singleton(){}       
 
    public static Singleton getInstance(){       
        if(singleton == null){                  // 1
            synchronized(Singleton.class){      // 2
                if(singleton == null){          // 3
                    singleton = new Singleton(); // 4
                }
            }
        } 
        return singleton;           
    }
}


双重检查加锁的单例模式代码上就比较复杂,尤其体现在getInstance方法上,包括两次检查singleton是否是null,一次加锁,singleton用关键字volatile修饰。为什么写一个单例如此复杂呢?

首先是懒汉模式,实例的初始化延迟到getInstance方法中,为了保证只会生成一个实例,要先判断singleton是否已经初始化,如果已经初始化了,就返回singleton,没有的话就创建对象。这就是1的作用。如果是单线程的情况,这样就够用了。

在多线程的情况下,只有1,没有2,3,就可能导致创建多个实例。例如,线程A和线程B调用getInstance方法,线程A先判断了1,然后时间片结束了,切换到线程B,线程B判断1,然后创建了singleton。时间片有切会线程A,线程A创建实例。这样就线程A和线程B就分别创建了一个实例了。破坏了单例的结构。

为了解决这个问题,加了synchronized保证只有一个线程进入临界区。那只有2,没有3,可以吗?还是考虑和前面一模一样的场景,这次线程A和线程B都判断了1了,进入2,线程A先进入临界区,线程B发现线程A进入了临界区,就挂在了Singleton.class等等待队列中,等待线程A执行完成。线程A继续执行,创建了一个singleton实例。退出了临界区。然后线程B被唤醒,进入临界区,又创建了一个singleton实例。结果又创建了两个singleton实例。

所以3的作用很明显了。在上面例子中,如果线程B发现实例已经被创建了(singleton不等于null),就直接退出临界区了。那1和3的作用似乎有点重合了,1似乎就不是必须了。2,3确实就足够保证单例了。但是加锁是比较消耗资源的,1就是为了减少资源的消耗。

最后,这么看来1,2,3,4就足以保证单例了。那为什么需要加volatile呢?volatile就牵扯到指令重排序的问题了。

要理解为什么要加volatile,首先要理解new Singleton()做了什么。

new一个对象有几个步骤。

1.看class对象是否加载,如果没有就先加载class对象,
2.分配内存空间,初始化实例,
3.调用构造函数,
4.返回地址给引用。
而cpu为了优化程序,可能会进行指令重排序,打乱这3,4这几个步骤,导致实例内存还没分配,就被使用了。

再用线程A和线程B举例。线程A执行到new Singleton(),开始初始化实例对象,由于存在指令重排序,这次new操作,先把引用赋值了,还没有执行构造函数。这时时间片结束了,切换到线程B执行,线程B调用new Singleton()方法,发现引用不等于null,就直接返回引用地址了,然后线程B执行了一些操作,就可能导致线程B使用了还没有被初始化的变量。

加了volatile之后,就保证new 不会被指令重排序。

至此,这就是一个完整的懒汉模式—>线程安全的->双重检查加锁单例模式。

回答: 如果你的电脑上没有目录C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Lib,那么可能是因为你没有安装Microsoft SDKs或者安装的版本不同。请确保你已经正确安装了Microsoft SDKs,并且检查你的安装路径是否与引用中提到的路径一致。如果你没有安装Microsoft SDKs或者安装的版本不同,你可以尝试根据你的需求下载并安装相应的SDK版本。 #### 引用[.reference_title] - *1* [QT :-1: error: LNK1104: 无法打开文件“shell32.lib”](https://blog.csdn.net/anhuihbo/article/details/131255124)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [DirectShow+VS2010+Win7配置说明](https://blog.csdn.net/az44yao/article/details/94651771)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Windows SDK 7.1 (包含directshow)安装配置](https://blog.csdn.net/u013051748/article/details/44831215)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值