1、单例模式

  • 饿汉式
package com.liuxiang.Singleton;

//一上来就创建对象
public class TestSingleton {

    //饿汉式 构造器私有 避免别人创建对象
    private TestSingleton(){

    }
    // 饿汉式可能会造成浪费空间
    private final static TestSingleton singleton = new TestSingleton();

    public static TestSingleton getInstance(){
        return singleton;
    }
    
}
  • 懒汉式
package com.liuxiang.Singleton;

public class TestSingleton {

    //构造器私有 避免别人创建对象
    private TestSingleton(){

    }
    // 懒汉式可能会造成浪费空间 volatile确保不会被指令重排
    private volatile  static TestSingleton singleton;

    public static TestSingleton getInstance(){
        if (singleton == null){
            //多线程获取 需要使用synchronized 双重检测锁模式
            synchronized (TestSingleton.class){
                if (singleton == null){
                    singleton = new TestSingleton();
                    //DCL懒汉式双重检测机制,在极端情况下还是会出现问题
                    //new一个对象在正常情况下的执行流程应该是:
                    //1.分配内存空间
                    //2.执行构造方法,初始化对象
                    //3.把这个对象指向这个空间
                    //如果出现了指令重排123 变成了132 就会出现问题
                    //所以我们应该加上volatile确保不会发生指令重排
                }
            }
        }
        return singleton;
    }

}
  • 使用枚举确保单例模式不被反射破坏
package com.liuxiang.Singleton;

import java.lang.reflect.Constructor;

public class TestSingleton {

    //构造器私有 避免别人创建对象
    private TestSingleton(){

    }
    // 懒汉式可能会造成浪费空间 volatile确保不会被指令重排
    private volatile  static TestSingleton singleton;

    public static TestSingleton getInstance(){
        if (singleton == null){
            //多线程获取 需要使用synchronized 双重检测锁模式
            synchronized (TestSingleton.class){
                if (singleton == null){
                    singleton = new TestSingleton();
                }
            }
        }
        return singleton;
    }

    //使用反射创建对象 破坏单例模式
    public static void main(String[] args) throws Exception {
        Constructor<TestSingleton> declaredConstructor = TestSingleton.class.getDeclaredConstructor(null);
        declaredConstructor.setAccessible(true);//关闭安全检测
        TestSingleton singleton1 = declaredConstructor.newInstance();//通过反射创建对象
        TestSingleton singleton2 = declaredConstructor.newInstance();//通过反射创建对象
        System.out.println(singleton1);
        System.out.println(singleton2);
    }

}
com.liuxiang.Singleton.TestSingleton@1b6d3586
com.liuxiang.Singleton.TestSingleton@4554617c

使用反射就可以绕过私有变量创建新的对象,我们查看反射的源码可以发现:反射机制不能操作枚举类

Java23种设计模式_单例模式