单例模式(懒汉模式-双检锁、饿汉模式、静态内部类模式)-详细

本文详细介绍了Java中的单例模式,包括懒汉模式(双检锁实现)、饿汉模式和静态内部类模式。通过示例代码展示了各种模式的实现细节,解释了为何在懒汉模式中使用双重检查锁定以及volatile关键字的重要性。最后,总结了静态内部类模式在保证线程安全的同时延迟加载,兼顾懒汉和饿汉模式的优点,推荐使用静态内部类模式实现单例。
摘要由CSDN通过智能技术生成

前言

  如果您觉得有用的话,记得给博主点个赞,评论,收藏一键三连啊,写作不易啊^ _ ^。
  而且听说点赞的人每天的运气都不会太差,实在白嫖的话,那欢迎常来啊!!!


单例模式(懒汉模式-双检锁、饿汉模式、静态内部类模式)-详细

01 单例模式是什么?

单例模式即每一个类都有一个实例
使用场景:线程池、链接池。

02 单例模式的好处?

java 中单例模式带来两个好处:
1.对于频繁使用的对象,可以省略创建对象所花费的时间,这对于那些重量级的对象而言,是非常可观的一笔系统开销。
2.由于new操作的次数减少,因而对系统内存的使用频率也会降低,这将减轻GC压力,缩短GC停顿时间。

03 单例模式的三种模式

1、懒汉模式
2、饿汉模式
3、静态内部类
注:推荐使用静态内部类模式使用单例。

03::01 懒汉模式

实现步骤:
1、构造函数私有化–防止外面直接调用;
2、制作一个返回单例方法;
3、实现一个单例类对象 ,并在前面加上volatile;
4、判断-如果该单例对象为空,实例化一个对象(第一次检查);
5、为了防止多线程场景下多个线程同时访问,多次初始化单例类对象,初始化实例对象前加一把锁;
6、为了防止多线程场景下多个线程第一个检查校验过去,走下面的锁竞争后,依次创建实例,违反单例原则, 而在加一次检查的目的是只有为空的时候创建单例对象(第二次检查);
7、!= null 直接返回;
这就是饿汉模式-双检锁。

实例:

class LanSingleton{
    private volatile static LanSingleton instance;
    //
    private LanSingleton(){}

    public static LanSingleton getInstance(){
        if (instance == null){
            synchronized (LanSingleton.class){
                if (instance == null){
                    instance = new LanSingleton();
                }
            }
        }
        return instance;
    }

}

测试:

/**
* @description: TODO 懒汉模式-双检锁
* @author 杨镇宇
* @date 2022/2/28 15:08
* @version 1.0
*/

public class LanSingletonTest {
    public static void main(String[] args) {
        new Thread(()->{
            System.out.println(LanSingleton.getInstance());
        }).start();
        new Thread(()->{
            System.out.println(LanSingleton.getInstance());

        }).start();
    }

}

效果:

在这里插入图片描述

03::01::01 问:为什么不在方法上加锁,而是在方法内部加锁?

因为直接在方法上加锁,相当于每次线程调用过来都要等上一个线程执行完毕,实际消耗时间太大。

03::01::02 问:单例类对象前面为什么要加volatile 关键字

JVM加载会有重排序的问题,因为CPU为了加载执行速度,会根据自己的优化策略,有些代码会进行优化,即重排序, * 而volatile有防止重排序的特点。


03::02 饿汉模式

特点:立即加载就会使用类,使用类加载机制保障单例模式,因为类加载的时候静态变量就已经加载成功。

实例:

class ESingleton{
    private static final ESingleton instance = new ESingleton();

    private ESingleton(){}

    public static ESingleton getInstance(){
        return instance;
    }
}

测试:

/**
* @description: TODO 饿汉模式 立即加载就会使用类,给予类加载机制保障单例模式
* @author 杨镇宇
* @date 2022/2/28 15:40
* @version 1.0
*/

public class ESingletonTest {
    public static void main(String[] args) {
        new Thread(()->{
            System.out.println(ESingleton.getInstance());
        }).start();
        new Thread(()->{
            System.out.println(ESingleton.getInstance());

        }).start();
    }
}

效果:
在这里插入图片描述


03::03 静态内部类模式

特点: 静态内部类也是给予类加载机制保证单例模式。

实例:

class  ClassSingleton{
    private static class InnerClassSingletonHolder{
        private static ClassSingleton instance = new ClassSingleton();
    }
    private ClassSingleton(){

    }
    public static ClassSingleton getInstance(){
        return InnerClassSingletonHolder.instance;
    }
}

测试:

/**
* @description: TODO 静态内部类 给予类加载机制保障单例模式
* @author 杨镇宇
* @date 2022/2/28 15:59
* @version 1.0
*/

public class ClassSingletonTest {
    public static void main(String[] args) {
        new Thread(()->{
            System.out.println(ClassSingleton.getInstance());
        }).start();
        new Thread(()->{
            System.out.println(ClassSingleton.getInstance());

        }).start();
    }
}

效果:
在这里插入图片描述


03::04 总结

对于静态内部类模式来说,保证线程安全的前提下,有点懒汉模式的味道,即不调用这个getInstance方法时,就不会加载这个类InnerClassSingletonHolder,也就不会浪费空间,而饿汉模式,就会马上加载,会浪费空间,但是它保证单例模式跟饿汉模式一样都是给予JVM的类加载机制保证单例模式,所以有点兼容懒汉模式和饿汉模式的味道,因此使用的话,推荐使用静态内部类模式来写单例模式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

栗子~~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值