Play with singleton mode

Play with singleton mode

Hungry Chinese style DCL lazy man style, in-depth study

Hungry Chinese

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 Hungry(){
    
    

    }

    private final static Hungry  hungry = new Hungry();

    private static Hungry getHungry(){
    
    
        return hungry;
    }
}

DCL lazy man

// 懒汉式单例
public class LazyMan {
    
    

    private static boolean latte = false;

    private LazyMan(){
    
    
   
        synchronized (LazyMan.class){
    
    
            if (latte == false){
    
    
                latte = true;
            }else {
    
    
                throw new RuntimeException("不要试图使用反射破坏异常");
            }
        }
        // System.out.println(Thread.currentThread().getName() + " OK");
    }

    //private static LazyMan lazyMan;
    private volatile static LazyMan lazyMan;
 // 双重检测锁模式的 懒汉式单例  DCL懒汉式 
   public static LazyMan getInstance(){
    
    
        if(lazyMan==null){
    
    
            lazyMan = new LazyMan(); // 不是一个原子性操作 
        }
        return lazyMan;
    }

//    这里双重检测加锁是保证了操作原子性,只有一个线程能创建一个实例,其他线程无法创建第二个
//    volatile关键字是为了防止因为指令重排导致的多线程问题,有可能线程A创建一个实例,
//    虚拟机只执行了分配空间,对象地址引用这两步,这是线程B过来发现对象已经被创建了,但是获取到的对象是还没有被初始化的

    /*
    * 1.分配内存空间
    * 2、执行构造方法,初始化对象3、把这个对象指向这个空间
    * 123
    * 132 A
    *     B //此时LazyMan还没有完成构造
    */

    // 双重检测锁模式的 懒汉式单例 DCL
    public static LazyMan getInstance(){
    
    
        if (lazyMan==null) {
    
    
            synchronized (LazyMan.class) {
    
    
                if (lazyMan == null) {
    
    
                    lazyMan = new LazyMan(); // 不是一个原子性操作 
                }
            }
        }
        return lazyMan;
    }

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

    // 反射
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
    
    
        // LazyMan instance = LazyMan.getInstance();

        Field latte = LazyMan.class.getDeclaredField("latte");

        Constructor<LazyMan> constructor = LazyMan.class.getDeclaredConstructor(null);
        qinjiang.setAccessible(true);
        constructor.setAccessible(true);
        LazyMan lazyMan = constructor.newInstance(); // new一个对象 走的空参构造
        qinjiang.set(lazyMan,false);// 修改为false
        LazyMan instance = constructor.newInstance(); // new一个对象 走的空参构造
        System.out.println(instance);
        System.out.println(lazyMan);

    }
}

/** * 1. 分配内存空间 
*     2、执行构造方法,初始化对象 
*     3、把这个对象指向这个空间 
* * 123 
* 132 A *     
B // 此时lazyMan还没有完成构造 */

Static inner class

// 静态内部类
public class Holder {
    
    
    public Holder(){
    
    

    }

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

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

Singleton is not safe because of reflection

Use enum

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

    INSTANCE;

    public EnumSingle getInstance(){
    
    
        return INSTANCE;
    }
}

class Test{
    
    
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
    
    
        EnumSingle instance1 = EnumSingle.INSTANCE;
        Constructor<EnumSingle> constructor = EnumSingle.class.getDeclaredConstructor(String.class,int.class);
        constructor.setAccessible(true);
        EnumSingle instance2 = constructor.newInstance();

        // NoSuchMethodException
        System.out.println(instance1);
        System.out.println(instance2);
    }
}

Insert picture description here

The final original code of the enumeration type

// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: EnumSingle.java
public final class EnumSingle extends Enum
{
    
    
    public static EnumSingle[] values()
    {
    
    
        return (EnumSingle[])$VALUES.clone();
    }
    public static EnumSingle valueOf(String name)
    {
    
    
        return (EnumSingle)Enum.valueOf(com/kuang/single/EnumSingle, name);
    }
    private EnumSingle(String s, int i)
    {
    
    
        super(s, i);
    }
    public EnumSingle getInstance()
    {
    
    
        return INSTANCE;
    }
    public static final EnumSingle INSTANCE;
    private static final EnumSingle $VALUES[];
    static
    {
    
    
        INSTANCE = new EnumSingle("INSTANCE", 0);
        $VALUES = (new EnumSingle[] {
    
    
                INSTANCE
        });
    }
}

Insert picture description here

Guess you like

Origin blog.csdn.net/qq_43803285/article/details/115387350