五种单例模式

在整个程序中,保持只有一个实例对象,就是单例模式。

单例模式可以减少构建,GC的次数,提升性能,还能减少堆内存的开销。

1. 懒汉式

  • 在需要使用对象的时候,才进行创建

  • 通过private构造方法,确保外部不能new出对象,通过一个静态方法进行对象获取。

public  class LazySingleton implements Serializable {
    private static LazySingleton lazySingleton = null;

    private  LazySingleton() {
    }

    public  static LazySingleton  getInstance(){
        if(lazySingleton == null){
            lazySingleton = new LazySingleton();
        }
        return lazySingleton;
    }
}

 需要注意的是,懒汉式是线程不安全的,并发情况下有线程安全问题,需要进行同步处理。

可以在getInstance()方法上加上synchronized。但是锁的粒度很大,所以引出了双重检查锁

2. 双重检查锁

  • 通过两个if判断,加上同步锁进行实现
  • 只进行一次判断上锁的话,上锁解锁后,单例对象就被重置了,因为有可能多个线程同时都通过了第一次判断,只是没抢到锁
  • 而且,需要加上volatile保证可见性和同步性,因为锁住的是class对象,不是单例对象,所以JMM保证的unlock刷到主存,lock读到工作内存只对class对象起作用,单例对象的可见性无法保证,同样的,是class对象的unlock操作在lock操作之前,happens before原则也无法保证有序性,因为整个临界区内根本找不到一个和class对象相关的操作。
public class DoubleCheckSingleton {
    private static volatile  DoubleCheckSingleton doubleCheckSingleton ;
    private DoubleCheckSingleton(){

    }

    public static DoubleCheckSingleton getInstance(){
        if(doubleCheckSingleton ==null){
            synchronized (DoubleCheckSingleton.class){
                if (doubleCheckSingleton == null){
                    doubleCheckSingleton = new DoubleCheckSingleton();
                }
            }
        }

        return doubleCheckSingleton;
    }
}

 3. 静态内部类

双重检查锁对于同步控制特别的复杂繁琐,有没有什么底层已经进行了的同步操作可以利用的呢?

答案是类加载的loadclass是被synchronized修饰的,类的加载是同步的,类加载进行到初始化部分的时候会对静态变量赋初始值,也会执行静态代码块。

  • 在单例类中,通过私有的静态内部类,创建单例对象

  • 静态内部类只有在被调用的时候才会被加载,实现了懒加载。

public class StaticInnerClassSingleton {

    /**
     * 第一次被调用到的时候才会进行类加载,进行初始化(JVM相关知识,加载、连接(验证,准备,解析)、初始化(为静态变量赋值)
     */
    private static class InnerClass{
        private static final StaticInnerClassSingleton staticInnerClassSingleton = new StaticInnerClassSingleton();
    }

    private StaticInnerClassSingleton(){
        System.out.println("StaticInnerClassSingleton初始化......");
    }

    public static StaticInnerClassSingleton getInstance(){
        return InnerClass.staticInnerClassSingleton;
    }
}

4. 饿汉式

如果不追求懒加载,那么还是使用类加载的同步控制的话,直接在单例类放一个静态变量,或者在静态代码块进行初始化。

public class HungrySingleton {

    private static final HungrySingleton hungrySingleton ;
    static {
        hungrySingleton = new HungrySingleton();
    }

    private HungrySingleton(){
        System.out.println("HungrySingleton初始化.....");
    }

    public static HungrySingleton getInstance(){
        return hungrySingleton;
    }
}

5. 枚举

前面一步一步的推导出到了饿汉式,看着很完美了,但是单例模式会被反射破坏。通过反射获取到构造函数后,可以强制开启权限执行。序列化和反序列化也都是基于反射创建对象的。

那么什么单例模式不会有这样的情况呢?

枚举。枚举是最佳的单例模式实现方式。

枚举在底层的构造函数是强制private的,反射无法打开权限,枚举对象的反序列化是通过name在堆内找到对应的对象

public enum EnumSingleton implements Serializable {
    EnumSingleton("枚举单例");

    private String name;

    EnumSingleton() {
    }

    EnumSingleton(String name) {
        this.name = name;
    }

    public void doSomething(String something) {
        System.out.println(name + ":" + something);
    }
}

相关推荐

  1. 模式

    2024-01-26 09:38:02       28 阅读
  2. 模式创建方式)

    2024-01-26 09:38:02       40 阅读
  3. 设计模式浅析() ·模式

    2024-01-26 09:38:02       31 阅读
  4. 模式的七写法

    2024-01-26 09:38:02       39 阅读
  5. C++模式(三方式)

    2024-01-26 09:38:02       12 阅读
  6. 26设计模式模式

    2024-01-26 09:38:02       23 阅读
  7. 设计模式——模式8实现

    2024-01-26 09:38:02       29 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-01-26 09:38:02       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-01-26 09:38:02       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-01-26 09:38:02       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-01-26 09:38:02       18 阅读

热门阅读

  1. Midjourney 生成图片教程

    2024-01-26 09:38:02       48 阅读
  2. C++(1) 命名空间

    2024-01-26 09:38:02       34 阅读
  3. 牛刀小试 - C++ 推箱子小游戏

    2024-01-26 09:38:02       38 阅读
  4. Android - 持久化方案

    2024-01-26 09:38:02       29 阅读
  5. MOJO中导入python模块

    2024-01-26 09:38:02       31 阅读
  6. 人工智能相关的政策文件都有哪些?--九五小庞

    2024-01-26 09:38:02       34 阅读
  7. Git管理秘籍:Python项目中的.gitignore策略

    2024-01-26 09:38:02       29 阅读
  8. Git命令总结

    2024-01-26 09:38:02       40 阅读
  9. PyTorch中self.layers的作用

    2024-01-26 09:38:02       29 阅读
  10. linux常用基础命令最新版

    2024-01-26 09:38:02       29 阅读
  11. linux bash shell的getopt以及函数用法小记

    2024-01-26 09:38:02       32 阅读
  12. bash 5.2中文修订 第十部分 安装Bash

    2024-01-26 09:38:02       26 阅读