Research on Java Singleton Pattern

Singleton mode

The hungry man DCL lazy man

Hungry Chinese

The private constructor program creates the object as soon as it comes up, resulting in -> may waste memory

//饿汉式单例,私有构造器
public class Hungry {
    
    
    //一上来就把这个全部加载可能会浪费内存

    private byte[] data1 = new byte[1024*1024];
    private byte[] data2 = new byte[1024*1024];
    private byte[] data3 = new byte[1024*1024];
    private byte[] data4 = new byte[1024*1024];
    private byte[] data5 = new byte[1024*1024];


    private Hungry(){
    
    

    }

    private final static Hungry HUNGRY = new Hungry();//一上来就new

    //一上来就把这个对象加载了
    public static Hungry getInstance(){
    
    
        return HUNGRY;
    }
}

DCL lazy man

In this single case, there is a problem with multi-thread concurrency.

  1. Allocate memory space
  2. Execute the constructor and initialize the object
  3. Attach this object to this space. The
    normal order 123 The
    real order may be 132.
    Thread A is fine .
    Thread B may have a problem.
//懒汉式单例
//结论: 道高一尺,魔高一丈
public class LazyMan {
    
    

    private static boolean swae_qj = false;//四重检测,加密

    //也是私有构造器
    private LazyMan(){
    
    

        //可以在此处解决-反射破坏单例问题,三重检测
        synchronized (LazyMan.class){
    
    
            if (swae_qj == false){
    
    //四重检测
                swae_qj = true;

            }else {
    
    
                throw new RuntimeException("不要试图使用反射破坏异常");

            }
        }

//        System.out.println(Thread.currentThread().getName() + "ok");
    }

    private volatile static LazyMan lazyMan;

    public static LazyMan getInstance(){
    
    
        //两次检测要加锁,因为这样会导致线程数量不确定
        //双重检测锁模式的 懒汉式单例  DCL懒汉式
        if (lazyMan==null){
    
    
            synchronized (LazyMan.class){
    
    
                if (lazyMan==null){
    
    //lazyman为空在创建
                    lazyMan = new LazyMan();//不是一个原子性操作
                    /**
                     * 1. 分配内存空间
                     * 2. 执行构造方法,初始化对象
                     * 3. 把这个对象执向这个空间
                     *
                     * 正常顺序         123
                     * 真实顺序可能是   132  线程A没问题
                     *                      线程B可能有问题
                     */
                }
            }
        }

        return lazyMan;//此时LazyMan还没有完成构造
    }
    //反射!
    public static void main(String[] args) throws Exception{
    
    
//        LazyMan instance = LazyMan.getInstance();

        Field swae_qj = LazyMan.class.getDeclaredField("swae_qj");
        swae_qj.setAccessible(true);//把它也破坏

        Constructor<LazyMan> declaredConstructors = LazyMan.class.getDeclaredConstructor(null);
        declaredConstructors.setAccessible(true);//无视私有构造器
        LazyMan instance = declaredConstructors.newInstance();//通过反射创建对象

        swae_qj.set(instance,false);

        LazyMan instance2 = declaredConstructors.newInstance();//通过反射创建对象

        System.out.println(instance);
        System.out.println(instance2);//反射可以破坏单例

    }

}
/*
  //单线程下OK
    //多线程并发
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(()->{
                LazyMan.getInstance();
            }).start();
        }
    }
 */

Static inner class

//静态内部类,只要是静态内部类就 构造器私有
public class Holder {
    
    

    private Holder(){
    
    

    }

    public static Holder getInstance(){
    
    
        return InnerClass.HOLDER;
    }

    public static class InnerClass{
    
    
        private static final Holder HOLDER = new Holder();
    }



}

Singleton is not safe, reflection

enumerate

//enum 是什么? 本身也是一个Class 类
public enum  EnumSingle {
    
    

    INSTANCE;//本身就是单例
    public EnumSingle getInstance(){
    
    
        return INSTANCE;//能保证我这个对象一定是唯一的吗?
    }

}

class Test{
    
    

    public static void main(String[] args) throws Exception{
    
    
        EnumSingle instance1 = EnumSingle.INSTANCE;
        //Cannot reflectively create enum objects
        //反射不能破坏Enum的单例
        Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(String.class,int.class);

        declaredConstructor.setAccessible(true);
        EnumSingle instance2 = declaredConstructor.newInstance();

        //NoSuchMethodException: com.swae.single.EnumSingle.<init>()
        //它说这个类 没有空参的构造器
        System.out.println(instance1);
        System.out.println(instance2);
    }

}

Parametric structure

Insert picture description here
The final decompiled source code of the enumeration type:
Insert picture description here
Conclusion: reflection cannot destroy the singleton of Enum

Guess you like

Origin blog.csdn.net/SwaeLeeUknow/article/details/112640821