01背景以我们常用办公软件WPS为例,我们使用的时候期望点击一次工具栏弹出一个对话框,再次点击的时候仍然是当前对话框,而不是出现多个对话框 。反映到编程中,其实就是对话框只被实例化一次,这就是单例模式的一个应用场景 。02概述单例模式(Singleton Pattern):单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法 。根据定义可知单例模式的要点有三个:
1、某个类只能有一个实例;
2、它必须自行创建这个实例;
3、它必须自行向整个系统提供这个实例 。
单例模式是一种对象创建型模式 。单例模式又名单件模式或单态模式 。
03实现3.1 饿汉式
饿汉法就是在第一次引用该类的时候就创建对象实例,而不管实际是否需要创建 。一上来就先实例化,但若类没有使用的话,就有点浪费资源类 。public class Singleton {
private static instance = new Singleton();
private Singleton() {}
public static getInstance() {
return m_instance;
}
}
优点:这样做的好处是编写简单,无需关注线程安全问题 。
缺点:
1、会生产出过多的实例对象,无论你是否要使用他们 。
2、无法做到延迟创建对象,但是我们很多时候都希望对象可以尽可能地延迟加载,从而减小负载,所以需要懒汉法 。
3.2 懒汉式
饿汉式(又称饱汉模式),很饱不着急,延迟加载,啥时候用啥时候创建实例,存在线程安全问题 。
实例在开始时为空,第一次加载后才实例化 。可节约一些资源,但在并发时有可能出现多个单例 。
优点:延时加载,用的时候才会生产对象 。
缺点:存在线程安全问题,需要保证同步,付出效率的代价 。
1、单线程实现
这种写法是最简单的,由私有构造器和一个公有静态工厂方法构成,在工厂方法中对singleton进行null判断,如果是null就new一个出来,最后返回singleton对象 。
public class Singleton {
private static Singleton singleton = null;//声明
private Singleton(){}
public static Singleton getSingleton() {
if(singleton == null) singleton = new Singleton();//实例化
return singleton;
}
}
优点:延迟加载,资源利用率高,不执行getInstance()就不会被实例化,可以执行该类的其他静态方法 。
缺点:第一次加载时不够快,线程不安全,多线程使用不必要的同步开销大 。
2、多线程实现
1)直接加锁Singleton* Singleton::getInstance() {
Lock lock;
if (nullptr == m_instance) {
m_instance = new Singleton();
}
return m_instance;
}
优点:线程安全 。
缺点:代价太高(整个判空和申请阶段全部都加锁,一劳永逸,但是效率低,锁范围太大) 。
2)双检查锁
双重锁模式,是饱汉模式的优化,进行双重判断,当已经创建过实例对象后就无需加锁,提高效率 。也是一种推荐使用的方式 。
Singleton* Singleton::getInstance() {
if (nullptr == m_instance) {
Lock lock;
if (nullptr == m_instance) {
m_instance = new Singleton();
}
}
return m_instance;
}
只有对象为空的时候才加锁,加完锁后再判空,防止在加锁的过程中被另一个线程调用new,即进行双检查:第一次检查是避免代价过高的问题,第二次检查是防止多线程问题 。
注:可以看出来与直接加锁相比,锁的范围缩小了,效率得以提升,同时通过在申请实例前加锁保证线程安全 。
推荐阅读
- 布隆过滤器原理及应用
- 雷凌有手动模式吗
- iphone11的飞行模式在哪里
- iphone11拍照夜间模式怎么关闭
- g5bootloader模式,韩版g5 root
- 奔驰g500怎样切换高速模式 奔驰g500怎么切换模式
- 苹果11pro夜景模式在哪里
- 三星盖世2用刷机精灵刷机后卡recovery模式
- 手机壳图片大全 可爱 背景图片 vivo手机壳图片大全
- 6大智慧功能值得一试,大智慧手机版本背景白