当前位置:网站首页>你真的懂单例模式么
你真的懂单例模式么
2022-08-02 13:13:00 【厚积薄发ض】
这里讲解单例模式中的懒汉模式和饿汉模式的注意事项及代码实现
目录
单例模式
单例模式就是只能有唯一一个实例
饿汉模式
什么是饿汉模式呢??
从字面理解上,一个饿汉很着急迫不及待的想吃饭.
举个栗子,如果进行读取10个G的文件,要是用饿汉模式就是一次性的将10个G的文件全部加载完成才可以看. ---->很着急 , 迫不及待
饿汉模式从类加载开始就创建出一个实例--->(很早的就创建实例-->立即加载)
代码实现:
//饿汉模式
public class Singleton {
//创建私有静态实例,让类加载时就创建出实例-->饿汉模式
private static Singleton instance = new Singleton();
private Singleton(){
//将构造方法设置为私有,保证其他类不能实例化对象(new实例)
}
//构造方法返回实例
public Singleton getInstance(){
return instance;
}
}
- 将instance利用static->从类加载的时候就创建出一个对象.
- 构造方法设置为私有不能让其他类再次new对象
- 返回实例
懒汉模式
懒汉模式与饿汉模式相反
懒汉模式 很缓慢 ~~ 不急迫~~
还是举个读取文件的栗子~~
还是要读取10个G的文件,懒汉模式是加载屏幕所能容纳的范围,能让用户看到的范围,当翻到下一张的时候,再次进行加载 -->效率很高->用多少~~~加载多少~~~
懒汉模式是 等待需要创建实例时在进行创建--->延迟加载
懒汉模式代码实现:
//实现懒汉模式
public class Singleton {
//1.使用volatile保证内存可见性和禁止指令重排序
//2.先将对象初始化为null,当需要实例化对象时在进行创建
private volatile static Singleton instance = null;
//设置构造方法
private Singleton(){
//私有构造方法,防止其他类实例化对象
}
//获取到实例
//1.使用双重if是为了降低竞争锁的概率
public Singleton getInstance(){
//外层if是用来判断实例有没有初始化好?
//1.如果已经初始化,不需要竞争锁,不进入if,直接往下执行
//2.如果没有初始化尝试竞争锁
if(instance==null){
//使用synchronized原因是
//1.防止多个线程同时创建,将读和写打包成一个原子->保证原子性,让其线程竞争锁
synchronized(Singleton.class){
//里层if: 当线程拿到锁之后,再来判断是否要真正的创建实例
if(instance==null){
instance = new Singleton();//实例化对象
}
}
}
return instance;
}
}
使用懒汉模式要注意三点
- 加锁
- 加上volatile关键字
- 双重if锁定
加锁的目的
因为在创建实例时有写线程在读,有些线程在写,所以很可能导致非原子操作,我们就把读和写打包成1个一个原子-->保证原子性,此时多个线程就要竞争锁
加上volatile关键字的作用
- 保证内存可见性
因为有的线程在读有的线程在写,很有可能编译器将其优化成读取寄存器,使得当一个线程修改,而每次读取时不能读取最新值,所以加上volatile
- 禁止指令重排序
因为要创建实例包含三个操作1.申请内存 2. 在内存上构造出实例 3.将地址赋值给对象的引用
编译器优化时,将2,3顺序颠倒,导致实例化出一个无效的对象,所以加上volatile关键字
双重if的目的
双重if最核心的是降低锁的竞争
里层if是保证实例唯一性,当线程拿到锁之后,判断是否要真正的创建实例,-->只能创建一次
外层if
- 保证是否已经创建好实例,如果已经创建好实例,就已经是线程安全,不要再次加锁,当线程安全时在进行加锁,会导致CPU速率下降,很可能造成堵塞,所以如果已经创建好实例,不用再次加锁已经是线程安全.
- 如果没有创建好实例,就尝试竞争锁
匿名内部类实现单例模式
public class InnerClassSingleton {
private InnerClassSingleton(){
//私有构造方法,防止其他类new对象
}
//创建内部类
private static final class SingletonHolder{
private static final InnerClassSingleton instance = new InnerClassSingleton();
}
//返回实例
public InnerClassSingleton getInstance(){
return SingletonHolder.instance;
}
}
使用枚举来实现单例模式
public enum EnumSingleton {
instance;
public EnumSingleton getInstance(){
return instance;
}
}
边栏推荐
- 【C语言】剖析函数递归(1)
- PHP+MYSQL [Student Information Management System] (Minimalist Edition)
- Basic operations of openGauss database (super detailed)
- 基于华为eNSP的企业网络规划
- 企业用直播平台能实现什么
- 基于 WeihanLi.Npoi 实现excel导入时纯汉字的日期转换
- 我的创作纪念日
- 【C语言】剖析函数递归(2)
- Detailed explanation of network flow (what information can the flow network diagram generally reflect)
- 基于flask商城的管理员功能
猜你喜欢
随机推荐
How to turn off hardware acceleration [easy to understand]
矩阵中的路径
svg balloon rises explosion js special effect
[C language] Analysis of function recursion (3)
Markdown怎么加入emoji
js true 3d histogram plugin
qt 编译报错 No rule to make target
鲁大师7月新机性能/流畅榜:性能跑分突破123万!
80篇国产数据库实操文档汇总(含TiDB、达梦、openGauss等)
[b01lers2020]Welcome to Earth-1
[C language] Analysis of function recursion (1)
智能手表前景如何?
我的创作纪念日
图论之Prim,最小生成树该怎么解?
RestTemplate use: set request header, request body
机器人碰撞检测方法形式化
微信小程序getPhoneNumber接口code=40013
leetcode 504. Base 7 七进制数 (简单)
Interpretation of new features | MySQL 8.0 GIPK invisible primary key
自动生成代码器推荐-code-gen