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

Posted 栗子~~

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单例模式(懒汉模式-双检锁饿汉模式静态内部类模式)-详细相关的知识,希望对你有一定的参考价值。

文章目录

前言

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


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

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的类加载机制保证单例模式,所以有点兼容懒汉模式和饿汉模式的味道,因此使用的话,推荐使用静态内部类模式来写单例模式。

以上是关于单例模式(懒汉模式-双检锁饿汉模式静态内部类模式)-详细的主要内容,如果未能解决你的问题,请参考以下文章

Java 设计模式 -- 单例模式的实现(饿汉式枚举饿汉式懒汉式双检锁懒汉式内部类懒汉式)jdk 中用到单例模式的场景DCL实现单例需用volatile 修饰静态变量

Java 设计模式 -- 单例模式的实现(饿汉式枚举饿汉式懒汉式双检锁懒汉式内部类懒汉式)jdk 中用到单例模式的场景DCL实现单例需用volatile 修饰静态变量

单例模式

java之设计模式

设计模式单例模式

设计模式单例模式