你真的懂单例模式么

这里讲解单例模式中的懒汉模式和饿汉模式的注意事项及代码实现

目录

单例模式

饿汉模式

懒汉模式

匿名内部类实现单例模式

使用枚举来实现单例模式


单例模式

单例模式就是只能有唯一一个实例

饿汉模式

什么是饿汉模式呢??

从字面理解上,一个饿汉很着急迫不及待的想吃饭.

举个栗子,如果进行读取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;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值