前言
👏作者简介:我是笑霸final,一名热爱技术的在校学生。
📝个人主页:个人主页1 || 笑霸final的主页2 📕系列专栏:计算机基础专栏
📧如果文章知识点有错误的地方,请指正!和大家一起学习,一起进步👀
🔥如果感觉博主的文章还不错的话,👍点赞👍 + 👀关注👀 + 🤏收藏🤏

设计模式——创建型模型——单列模式(8种实现)_饿汉式

目录

  • 一、单例模式定义
  • 特点
  • 二、单列模式分类
  • 三、饿汉式【可用】
  • 3.1饿汉式(静态常量)
  • 3.2饿汉式(静态代码块)
  • 四、懒汉式【不可用】
  • 4.1懒汉式(线程不安全)【不可用】
  • 4.2懒汉式(线程安全,同步方法)【不可用】
  • 4.3 懒汉式(线程安全 ,同步代码块)【不可用】
  • 五、双重检查
  • volatile
  • 六、静态内部类
  • 七、枚举
  • 八、适用场景:

一、单例模式定义

单例模式(Singleton Pattern):属于创建类型的一种常用的软件设计模式。通过单例模式的方法创建的类在当前进程中只有一个实例

特点

  • a、单例类只能有一个实例。
  • b、单例类必须自己创建自己的唯一实例。
  • c、单例类必须给所有其他对象提供这一实例。
  • 单例模式保证了全局对象的唯一性,比如系统启动读取配置文件就需要单例保证配置的一致性。

二、单列模式分类

设计模式代码仓库

  • 1.饿汉式(静态常量)【可用】
  • 2.饿汉式(静态代码块)【可用】
    饿汉式都可能造成内存的浪费
  • 3.懒汉式(线程不安全)【不可用】
  • 4.懒汉式(线程安全,同步方法)【不可用】
  • 5.懒汉式(线程安全,同步代码块)【不可用】[
  • 6.双重检查【推荐使用】
  • 7.静态内部类【推荐使用】
  • 8.枚举【推荐使用】[枚举]

三、饿汉式【可用】

下面两种方式都可用 但是都可能造成内存的浪费

3.1饿汉式(静态常量)

  • 饿汉式(静态变量)【可用】
    ====================================================================
  • 优点:这种写法比较简单,就是在类装载的时候就完成实例化。避免了步问题
  • 缺点:在类装载的时候就完成实例化,没有达到Lazy Loading(懒加载)的效果。
  • 如至终从未使用过这个实例,则会造成内存的浪费
class Singleton1{

    /**
     * 1.构造器私有化,防止外部new
     */
    private Singleton1(){}

    /**
     * 在内部创建实例对象
     * 在内加载的时候创建对象实例
     */
    private final static Singleton1 instance=new Singleton1();

    /**
     * 对外提供一个共有的静态方法返回这个实例
     */
    public static Singleton1 getInstance(){
        return instance;
    }
}

3.2饿汉式(静态代码块)

  • 饿汉式(静态代码块)【可用】================================================================
  • 优缺点:和饿汉式(静态变量)类似
  • 只不过将类实例化的过程放在了静态代码块中,
  • 也是在类装载的时候,就执行静态代码块中的代码,
  • 初始化类的实例。优缺点和上面是一样的。
class Singleton2{
    /**
     * 1.构造器私有化,防止外部new
     */
    private Singleton2(){}

    /**
     * 在静态代码块中创建实例对象
     */
    private static  Singleton2 instance;
    static {
        instance=new Singleton2();
    }

    /**
     * 对外提供一个共有的静态方法返回这个实例
     */
    public static Singleton2 getInstance(){
        return instance;
    }

}

四、懒汉式【不可用】

4.1懒汉式(线程不安全)【不可用】

  • 懒汉式(线程不安全 )【不可用】========================================================================
  • 优点:起到了Lazy Loading的效果,但是只能在单线程下使用。
  • 缺点:如果在多线程下,一个线程进入了if (singleton == null)判断语块,
  • 还未往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例在多线程环境下不可使用这种方式
class Singleton3{

    private Singleton3(){}

    private static  Singleton3 instance;

    /**
     * 提供一个静态公有方法,当使用该方法时。才去创建instance
     */
    public static  Singleton3 getInstance(){
        if(instance==null){
            //没有创建才去创建
            instance = new Singleton3();
        }
        //返回实例
        return instance;
    }

}

4.2懒汉式(线程安全,同步方法)【不可用】

  • 懒汉式(线程安全 ,同步方法)【不可用】========================================================================
  • 优点:解决了线程不安全问题
  • 缺点:效率太低了,每个线程在想获得类的实例时候,
  • 执行getlnstance()方法都要‘synchronized同步’。而其实这个方法只执行一次实例化代码就够了,
  • 后面的想获得该直接return就行了。方法进行同步效率太低
  • 结论:在实际开发中,效率低 不推荐使用这种方式
class Singleton4{

    private Singleton4(){}

    private static  Singleton4 instance;

    /**
     * 提供一个静态公有方法,加入了同步处理的代码 ,解决线程安全问题
     * 当使用该方法时。才去创建instance
     */
    public static synchronized Singleton4 getInstance(){
        if(instance==null){
            //没有创建才去创建
            instance = new Singleton4();
        }
        //返回实例
        return instance;
    }

}

4.3 懒汉式(线程安全 ,同步代码块)【不可用】

  • 懒汉式(线程安全 ,同步代码块)【不可用】========================================================================
  • 但是这种同步并不能起到线程同步的作用。跟第Singleton3实现方式遇到的情形一致,
  • 假如一个线程进入了if (singleton == null)判断语句块,还未来得及往下执行,
  • 另一个线程也通过了这个判断语句,这时便会产生多个实例。
class Singleton5{

    private Singleton5(){}

    private static  Singleton5 instance;

    /**
     * 提供一个静态公有方法,加入了同步处理的代码 ,解决线程安全问题
     * 当使用该方法时。才去创建instance
     */
    public static  Singleton5 getInstance(){
        if(instance==null){
            synchronized(Singleton5.class){
                instance = new Singleton5();
            }
        }
        //返回实例
        return instance;
    }

}

五、双重检查

  • 双重检查=========================================================================

优点说明:

  • Double-Check概念是多线程开发中常使用到的,如代码中所示,
  • 我们进行次if (singleton == null)检查,这样就可以保证线程安全了
  • 这样,实例化代码只用执行一次,后面再次访问时,判断if (singleton =null)直接return实例化对象,
  • 也避免的反复进行方法同步
  • 线程安全;延迟加载;效率较高
  • 结论: 在实际开发中,推荐使用这种单例设计模式
class Singleton6{

    private static volatile Singleton6 instance;
    private Singleton6(){}

    /**
     * 提供一个静态公有方法,加入双重检查的代码 ,解决线程安全问题,同时解决懒加载问题
     * 也保证了效率
     */
    public static synchronized Singleton6 getInstance(){
        if(instance==null){
            synchronized(Singleton6.class){
                if(instance==null){
                    instance = new Singleton6();
                }
            }
        }
        //返回实例
        return instance;
    }

}

volatile

volatile 是Java提供的一种轻量级的同步机制。Java 语言包含两种内在的同步机制:同步块(或方法)和 volatile 变量,相比于synchronized(synchronized通常称为重量级锁),volatile更轻量级,因为它不会引起线程上下文的切换和调度。但是volatile 变量的同步性较差(有时它更简单并且开销更低),而且其使用也更容易出错。

下面简单总结一下volatile的作用:

  • 它会强制将对缓存的修改操作立即写入主存,让所有的线程可见;
  • 它确保指令重排序时不会把其后面的指令排到内存屏障之前的位置,也不会把前面的指令排到内存屏障的后面;即在执行到内存屏障这句指令时,在它前面的操作已经全部完成;
  • 如果是写操作,它会导致其他CPU中对应的缓存行无效。

六、静态内部类

  • 这种方式跟饿汉式方式采用的机制类似,但又有不同。
  • 两者都是采用了类装载的机制来保证初始化实例时只有一个线程。
  • 不同的地方在饿汉式方式是只要Singleton类被装载就会实例化,
  • 没有Lazy-Loading的作用,而静态内部类方式在Singleton类被装载时并不会立即实例化,
  • 而是在需要实例化时,调用getInstance方法,才会装载SingletonInstance类,从而完成Singleton的实例化。
  • 类的静态属性只会在第一次加载类的时候初始化,
  • 所以在这里,JVM帮助我们保证了线程的安全性,在类进行初始化时,别的线程是无法进入的。
class Singleton7 {

    private Singleton7() {
    }


    /**
     * 静态内部类
     */
    private static class SingletonInstance {
        private static final Singleton7 INSTANCE = new Singleton7();
    }

    public static Singleton7 getInstance() {
        return SingletonInstance.INSTANCE;
    }

}
  • 特点:
  • 1.外部类装载时 静态内部类不会立即被装载
  • 2.调用getInstance() 静态内部类才会被装载而且只会装载一次
  • 优点:避免了线程不安全,延迟加载,效率高。

七、枚举

借助JDK1.5中添加的枚举来实现单例模式。不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象

public class Enumeration {
    public static void main(String[] args) {

        Singleton singleton1 = Singleton.INSTANCE;
        Singleton singleton2 = Singleton.INSTANCE;
        System.out.println(singleton1==singleton2);
        System.out.println(singleton1.hashCode());
        System.out.println(singleton2.hashCode());
    }
}


/**
 * 枚举========================
 *
 * 借助JDK1.5中添加的枚举来实现单例模式。不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象
 */
enum Singleton{
    //属性
    INSTANCE;
    public void sayOK(){}
}

设计模式——创建型模型——单列模式(8种实现)_java_02

八、适用场景:

单例模式只允许创建一个对象,因此节省内存,加快对象访问速度,因此对象需要被公用的场合适合使用,如多个模块使用同一个数据源连接对象等等。如:

  • 需要频繁实例化然后销毁的对象。
  • 创建对象时耗时过多或者耗资源过多,但又经常用到的对象。
  • 有状态的工具类对象。
  • 频繁访问数据库或文件的对象。

功有所不全,力有所不任,才有所不足。欢迎大家指正文中错误
设计模式代码仓库 欢迎start====》设计模式代码仓库