单例模式

定义:一个类只有一个实例
分类:单例模式可分为三大类-八小类:

  • 饿汉式
    • 静态常量(推荐)
    • 静态代码块(推荐)
  • 懒汉式
    • 线程不安全
    • 线程安全,同步方法
    • 线程安全,同步代码块
    • 双重检查(推荐)
    • 静态内部类(推荐)
  • 枚举 (推荐)

对比:

模式 描述 方式 优点 缺点 是否推荐
饿汉模式(2) 不管需不需要用到实例都要去创建实例
1. 静态常量
1. 静态代码块
线程安全 浪费内存(没用到的情况下) 推荐
懒汉模式(5) 需要用到创建实例了程序再去创建实例 普通饿汉实现
线程不安全 不推荐
同步方法 线程安全 消耗性能(每次都要锁) 不推荐
同步代码块 减少了同步方法的性能消耗 线程不安全 不推荐
双重检查 线程安全
推荐
静态内部类 线程安全 推荐
枚举模式(1) - - 1. 解决线程同步
2. 防止反序列化
原因:由于枚举没有构造方法,不会被反射
反射原理:类的class文件加载到内存,反射(反序列化的方式)new一个实例(前提要有构造方法)

推荐(完美中的完美)

剖析原理

分析实现步骤

  1. 构造器私有化
  2. 创建对象实例
  3. 提供公共的静态方法,返回实例对象

    代码实现

    饿汉模式

    不管需不需要用到实例都要去创建实例

    静态常量

    1. /**
    2. * 单例 - 饿汉模式 - 静态常量
    3. */
    4. public class SingletonByStaticConst {
    5. //私有化构造器
    6. private SingletonByStaticConst() {}
    7. //静态常量
    8. private final static SingletonByStaticConst INSTANCE = new SingletonByStaticConst();
    9. //公共获取实例方法
    10. public static SingletonByStaticConst getInstance(){
    11. return INSTANCE;
    12. }
    13. }

    静态代码块

    /**
    *  单例 - 饿汉 - 静态代码块 
    */
    public class SingletonByStaticBlock {
    
     //构造器私有化
     public SingletonByStaticBlock() {}
    
     //静态代码块
     private static SingletonByStaticBlock INSTANCE;
     static{
         INSTANCE = new SingletonByStaticBlock();
     }
     //公共获取实例方法
     public static SingletonByStaticBlock getInstance(){
         return INSTANCE;
     }
    }
    

    懒汉模式

    需要用到创建实例了程序再去创建实例

    线程不安全

    /**
    *  单例 - 懒汉 - 线程不安全
    */
    public class SingletonByLazyUnsafe {
    
     private static SingletonByLazyUnsafe instance;
     //私有化构造器
     private SingletonByLazyUnsafe() {}
     //公共获取实例方法
     public static SingletonByLazyUnsafe getInstance(){
         if(null == instance){
             //存在线程安全问题,不推荐
             instance = new SingletonByLazyUnsafe();
         }
         return instance;
     }
    }
    

    同步方法

    ```java /**

    • 单例 - 懒汉 - 同步方法 */ public class SingletonByLazySyncMethord {

      private static SingletonByLazySyncMethord instance; //私有化构造器 private SingletonByLazySyncMethord() {} //公共获取实例方法 public static synchronized SingletonByLazySyncMethord getInstance(){ if(null == instance){

        instance = new SingletonByLazySyncMethord();
      

      } return instance; } }

<a name="LdyGA"></a>
### 同步代码块
```java
/**
 * 单例 - 懒汉 - 同步代码块
 */
public class SingletonByLazySyncBlock {

    private static SingletonByLazySyncBlock instance;
    //私有化构造器
    private SingletonByLazySyncBlock() {}
    //公共获取实例方法
    public static SingletonByLazySyncBlock getInstance() {
        if (null == instance) {
            //解决了每次判锁的性能问题,但存在线程不安全问题
            synchronized (SingletonByLazySyncBlock.class) {
                instance = new SingletonByLazySyncBlock();
            }
        }
        return instance;
    }
}

双重检查

/**
 * 单例 - 懒汉 - 双重检查
 */
public class SingletonByLazyDoubleCheck {

    private static SingletonByLazyDoubleCheck instance;
    //私有化构造器
    private SingletonByLazyDoubleCheck() {}
    //公共获取实例方法
    public static SingletonByLazyDoubleCheck getInstance() {
        if (null == instance) {
            synchronized (SingletonByLazyDoubleCheck.class) {
                if(null == instance){
                    instance = new SingletonByLazyDoubleCheck();
                }
            }
        }
        return instance;
    }
}

静态内部类

/**
 * 单例 - 懒汉 - 静态内部类
 */
public class SingletonByLazyStaticInner {

    private static SingletonByLazyStaticInner instance;
    //私有化构造器
    private SingletonByLazyStaticInner() {}

    //静态内部类,初始化时不加载,只有使用的时候才会被加载
    private static class SingletonInstance{
        private static final SingletonByLazyStaticInner INSTANCE = new SingletonByLazyStaticInner();
    }

    //公共获取实例方法
    public static SingletonByLazyStaticInner getInstance() {
        return SingletonInstance.INSTANCE;
    }
}

枚举

/**
 * 单例 - 枚举
 */
public enum SingletonByEnum {
    INSTANT;
}

框架或项目源码分析

JDK中java.lang.Runtime类使用了单例,采用了饿汉模式的静态常量方式
image.png

应用场景

  • 重量级对象(需要频繁的进行创建和销毁对象)
  • 经常用到的对象
  • 工具类对象
  • 频繁访问数据库或文件的对象,例如:数据源、session工厂