Interview question learning: singleton mode

Purpose

In order to facilitate interview review, I prefer personal study summary, study notes, etc.

resource

A learning video about high-frequency interview questions at Station B

Method to realize

Hungry Chinese style

/**
 * 单例模式: 饿汉式
 *
 * @author xiaozhengN [email protected]
 * @since 2022-10-16 12:55:49
 **/
public class Singleton1 implements Serializable {
    
    
    // 饿汉式: 一开始就创建对象
    private static final Singleton1 INSTANCE = new Singleton1();

    /**
     * 构造方法私有化
     */
    private Singleton1() {
    
    
        // 规避反射去破坏单例对象
        if (INSTANCE != null) {
    
    
            throw new RuntimeException("单例对象不能重复创建");
        }
        System.out.println("私有的无参构造");
    }

    /**
     * 对外提供获取该对象的静态方法
     *
     * @return 单例对象
     */
    public static Singleton1 getInstance() {
    
    
        return INSTANCE;
    }

    /**
     * 模拟类其他方法
     */
    public static void otherMethod() {
    
    
        System.out.println("对象其他方法");
    }

    /**
     * 对象中重写 readResolve 方法, 规避反序列化破坏单例对象
     *
     * @return 单例对象
     */
    public Object readResolve() {
    
    
        return INSTANCE;
    }
}

enumerate Chinese style

/**
 * 枚举饿汉式
 *
 * @author xiaozhengN [email protected]
 * @since 2022-10-16 14:43:15
 **/
public enum Singleton2 {
    
    
    INSTANCE;

    // 枚举无参构造默认私用化
    Singleton2() {
    
    
        System.out.println("Singleton2 无参构造方法");
    }

    @Override
    public String toString() {
    
    
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }

    /**
     * 对外提供获取单例对象方法
     *
     * @return 单例对象
     */
    public static Singleton2 getInstance() {
    
    
        return INSTANCE;
    }

    /**
     * 模拟其他方法: 主要用于监测是否是饿汉式
     */
    public static void otherMethod() {
    
    
        System.out.println("Singleton2 其他方法");
    }
}

Lazy

/**
 * 懒汉式单例
 *
 * @author xiaozhengN [email protected]
 * @since 2022-10-16 15:55:24
 **/
public class Singleton3 implements Serializable {
    
    
    // 懒加载
    private static Singleton3 INSTANCE = null;

    // 构造方法私有
    private Singleton3() {
    
    
        // 规避反射去破坏单例对象
        if (INSTANCE != null) {
    
    
            throw new RuntimeException("单例对象不能重复创建");
        }
        System.out.println("Singleton3 无参构造方法");
    }

    /**
     * 对外提供获取该单例对象的方法
     *
     * @return 单例对象
     */
    public static synchronized Singleton3 getInstance() {
    
    
        if (INSTANCE == null) {
    
    
            INSTANCE = new Singleton3();
        }
        return INSTANCE;
    }

    /**
     * 模拟单例对象其他方法
     */
    public static void otherMethod() {
    
    
        System.out.println("main.daily.Singleton3.otherMethod");
    }

    /**
     * 对象中重写 readResolve 方法, 规避反序列化破坏单例对象
     *
     * @return 单例对象
     */
    public Object readResolve() {
    
    
        return getInstance();
    }
}

double search lazy

/**
 * 懒汉式单例-DCL(Double Checked Locked)
 *
 * @author xiaozhengN [email protected]
 * @since 2022-10-16 16:06:50
 **/
public class Singleton4 implements Serializable {
    
    
    // 懒加载
    // 有序性
    private static volatile Singleton4 INSTANCE = null;

    // 无参构造私有化
    private Singleton4() {
    
    
        if (INSTANCE != null) {
    
    
            throw new RuntimeException("单例对象不能重复创建");
        }
        System.out.println("Singleton4 无参构造");
    }

    /**
     * 对外提供获取该单例对象的方法
     *
     * @return 单例对象
     */
    public static Singleton4 getInstance() {
    
    
        if (INSTANCE == null) {
    
    
            synchronized (Singleton4.class) {
    
    
                if (INSTANCE == null) {
    
    
                    INSTANCE = new Singleton4();
                }
            }
        }
        return INSTANCE;
    }

    /**
     * 模拟单例对象其他方法
     */
    public static void otherMethod() {
    
    
        System.out.println("main.daily.Singleton4.otherMethod");
    }

    /**
     * 对象中重写 readResolve 方法, 规避反序列化破坏单例对象
     *
     * @return 单例对象
     */
    public Object readResolve() {
    
    
        return getInstance();
    }
}

It must be volatile, create objects, and the CPU may rearrange instructions

        17: new           #9                  // class main/daily/Singleton4
        20: dup
        21: invokespecial #10                 // Method "<init>":()V
        24: putstatic     #2                  // Field INSTANCE:Lmain/daily/Singleton4;

inner class lazy

/**
 * 懒汉式单例-内部类
 *
 * @author xiaozhengN [email protected]
 * @since 2022-10-16 16:52:51
 **/
public class Singleton5 implements Serializable {
    
    
    private Singleton5() {
    
    
        if (Holder.INSTANCE != null) {
    
    
            throw new RuntimeException("单例对象不能重复创建");
        }
        System.out.println("Singleton5 无参构造");
    }

    private static class Holder {
    
    
        static Singleton5 INSTANCE = new Singleton5();
    }

    /**
     * 对外提供获取该单例对象的方法
     *
     * @return 单例对象
     */
    public static Singleton5 getInstance() {
    
    
        return Holder.INSTANCE;
    }

    /**
     * 模拟单例对象其他方法
     */
    public static void otherMethod() {
    
    
        System.out.println("main.daily.Singleton5.otherMethod");
    }

    /**
     * 对象中重写 readResolve 方法, 规避反序列化破坏单例对象
     *
     * @return 单例对象
     */
    public Object readResolve() {
    
    
        return getInstance();
    }
}

Self Validation Test Class

/**
 * 单例模式测试类
 *
 * @author xiaozhengN [email protected]
 * @since 2022-10-16 13:14:31
 **/
public class TestSingleton {
    
    
    public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException, IOException, ClassNotFoundException {
    
    
        System.out.println("------------------------ Singleton1: 饿汉单例开始 ------------------------");
        Singleton1.otherMethod();
        System.out.println(Singleton1.getInstance());
        System.out.println(Singleton1.getInstance());
        destroySingletonByReflection(Singleton1.class, Singleton1.getInstance());
        destroySingletonBySerializable(Singleton1.getInstance(), Singleton1.getInstance().toString());
        destroySingletonByUnsafe(Singleton1.class, Singleton1.getInstance().toString());
        System.out.println("------------------------ Singleton1: 饿汉单例结束 ------------------------");

        System.out.println("------------------------ Singleton2: 枚举饿汉式开始 ------------------------");
        Singleton2.otherMethod();
        System.out.println(Singleton2.getInstance());
        System.out.println(Singleton2.getInstance());
        // 枚举可以自己规避反射去破坏单例
        destroySingletonByReflection(Singleton2.class, Singleton2.getInstance());
        // 枚举可以自己规避反序列化去破坏单例
        destroySingletonBySerializable(Singleton2.getInstance(), Singleton2.getInstance().toString());
        destroySingletonByUnsafe(Singleton2.class, Singleton2.getInstance().toString());
        System.out.println("------------------------ Singleton2: 枚举饿汉式结束 ------------------------");

        System.out.println("------------------------ Singleton3: 懒汉式开始 ------------------------");
        Singleton3.otherMethod();
        System.out.println(Singleton3.getInstance());
        System.out.println(Singleton3.getInstance());
        // 枚举可以自己规避反射去破坏单例
        destroySingletonByReflection(Singleton3.class, Singleton3.getInstance());
        // 枚举可以自己规避反序列化去破坏单例
        destroySingletonBySerializable(Singleton3.getInstance(), Singleton3.getInstance().toString());
        destroySingletonByUnsafe(Singleton3.class, Singleton3.getInstance().toString());
        System.out.println("------------------------ Singleton3: 懒汉式结束 ------------------------");

        System.out.println("------------------------ Singleton4: DCL懒汉式开始 ------------------------");
        Singleton4.otherMethod();
        System.out.println(Singleton4.getInstance());
        System.out.println(Singleton4.getInstance());
        // 枚举可以自己规避反射去破坏单例
        destroySingletonByReflection(Singleton4.class, Singleton4.getInstance());
        // 枚举可以自己规避反序列化去破坏单例
        destroySingletonBySerializable(Singleton4.getInstance(), Singleton4.getInstance().toString());
        destroySingletonByUnsafe(Singleton4.class, Singleton4.getInstance().toString());
        System.out.println("------------------------ Singleton4: DCL懒汉式结束 ------------------------");

        System.out.println("------------------------ Singleton5: 内部类懒汉式开始 ------------------------");
        Singleton5.otherMethod();
        System.out.println(Singleton5.getInstance());
        System.out.println(Singleton5.getInstance());
        // 枚举可以自己规避反射去破坏单例
        destroySingletonByReflection(Singleton5.class, Singleton5.getInstance());
        // 枚举可以自己规避反序列化去破坏单例
        destroySingletonBySerializable(Singleton5.getInstance(), Singleton5.getInstance().toString());
        destroySingletonByUnsafe(Singleton5.class, Singleton5.getInstance().toString());
        System.out.println("------------------------ Singleton5: 内部类懒汉式结束 ------------------------");
    }

    // Unsafe 破坏单例
    private static void destroySingletonByUnsafe(Class<?> singletonClass, String singletonStr) throws InstantiationException {
    
    
        Object obj = UnsafeUtils.getUnsafe().allocateInstance(singletonClass);
        System.out.println("反序列化是否已经被Unsafe破坏: " + !StrUtil.equals(obj.toString(), singletonStr));
    }

    // 反序列化破坏单例
    private static void destroySingletonBySerializable(Object instance, String singletonStr) throws IOException, ClassNotFoundException {
    
    
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(instance);
        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
        String newStr = ois.readObject().toString();
        System.out.println("反序列化是否已经被Serializable破坏: " + !StrUtil.equals(newStr, singletonStr));
    }

    // 反射破坏单例
    private static void destroySingletonByReflection(Class<?> singletonClass, Object singletonObj) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
    
    
        // 通过反射获取私有构造方法
        if (singletonObj instanceof Singleton1 || singletonObj instanceof Singleton3 || singletonObj instanceof Singleton4 || singletonObj instanceof Singleton5) {
    
    
            Constructor<?> declaredConstructor = singletonClass.getDeclaredConstructor();
            // 开启访问权限
            declaredConstructor.setAccessible(true);
            // 执行私有构造方法
            String newStr;
            try {
    
    
                newStr = declaredConstructor.newInstance().toString();
                System.out.println("单例模式是否已经被Reflection破坏: " + !StrUtil.equals(newStr, singletonObj.toString()));
            } catch (Exception e) {
    
    
                System.out.println("反射破坏单例模式, 已通过抛出异常规避!");
            }
        }

        if (singletonObj instanceof Singleton2) {
    
    
            Constructor<?> declaredConstructor = singletonClass.getDeclaredConstructor(String.class, int.class);
            // 开启访问权限
            declaredConstructor.setAccessible(true);
            String newStr;
            try {
    
    
                newStr = declaredConstructor.newInstance("OTHER", 3).toString();
                System.out.println("单例模式是否已经被Reflection破坏: " + !StrUtil.equals(newStr, singletonObj.toString()));
            } catch (Exception e) {
    
    
                System.out.println("反射破坏枚举单例模式, 已通过抛出异常规避!");
            }
        }
    }
}

self test results

------------------------ Singleton1: 饿汉单例开始 ------------------------
私有的无参构造
对象其他方法
main.daily.Singleton1@6ff3c5b5
main.daily.Singleton1@6ff3c5b5
反射破坏单例模式, 已通过抛出异常规避!
反序列化是否已经被Serializable破坏: false
反序列化是否已经被Unsafe破坏: true
------------------------ Singleton1: 饿汉单例结束 ------------------------
------------------------ Singleton2: 枚举饿汉式开始 ------------------------
Singleton2 无参构造方法
Singleton2 其他方法
main.daily.Singleton2@1e80bfe8
main.daily.Singleton2@1e80bfe8
反射破坏枚举单例模式, 已通过抛出异常规避!
反序列化是否已经被Serializable破坏: false
反序列化是否已经被Unsafe破坏: true
------------------------ Singleton2: 枚举饿汉式结束 ------------------------
------------------------ Singleton3: 懒汉式开始 ------------------------
main.daily.Singleton3.otherMethod
Singleton3 无参构造方法
main.daily.Singleton3@79fc0f2f
main.daily.Singleton3@79fc0f2f
反射破坏单例模式, 已通过抛出异常规避!
反序列化是否已经被Serializable破坏: false
反序列化是否已经被Unsafe破坏: true
------------------------ Singleton3: 懒汉式结束 ------------------------
------------------------ Singleton4: DCL懒汉式开始 ------------------------
main.daily.Singleton4.otherMethod
Singleton4 无参构造
main.daily.Singleton4@378fd1ac
main.daily.Singleton4@378fd1ac
反射破坏单例模式, 已通过抛出异常规避!
反序列化是否已经被Serializable破坏: false
反序列化是否已经被Unsafe破坏: true
------------------------ Singleton4: DCL懒汉式结束 ------------------------
------------------------ Singleton5: 内部类懒汉式开始 ------------------------
main.daily.Singleton5.otherMethod
Singleton5 无参构造
main.daily.Singleton5@7c3df479
main.daily.Singleton5@7c3df479
反射破坏单例模式, 已通过抛出异常规避!
反序列化是否已经被Serializable破坏: false
反序列化是否已经被Unsafe破坏: true
------------------------ Singleton5: 内部类懒汉式结束 ------------------------

The source code embodying the singleton mode in JDK

java.lang.Runtime#getRuntime

Constructor privatization

    /** Don't let anyone else instantiate this class */
    private Runtime() {
    
    }

Hungry Chinese style singleton

private static Runtime currentRuntime = new Runtime();

Provide external APIs to obtain singleton alignment:

    /**
     * Returns the runtime object associated with the current Java application.
     * Most of the methods of class <code>Runtime</code> are instance
     * methods and must be invoked with respect to the current runtime object.
     *
     * @return  the <code>Runtime</code> object associated with the current
     *          Java application.
     */
    public static Runtime getRuntime() {
    
    
        return currentRuntime;
    }

java.lang.System#console

Constructor private:

    /** Don't let anyone instantiate this class */
    private System() {
    
    
    }

Console abstracts the console, volatile prevents CPU instruction rearrangement

private static volatile Console cons = null;

Get singleton object API:

    /**
     * Returns the unique {@link java.io.Console Console} object associated
     * with the current Java virtual machine, if any.
     *
     * @return  The system console, if any, otherwise <tt>null</tt>.
     *
     * @since   1.6
     */
     public static Console console() {
    
    
         if (cons == null) {
    
    
             synchronized (System.class) {
    
    
                 cons = sun.misc.SharedSecrets.getJavaIOAccess().console();
             }
         }
         return cons;
     }

java.util.Collections.EmptySet

    public static final Set EMPTY_SET = new EmptySet<>();
    private static class EmptySet<E>
        extends AbstractSet<E>
        implements Serializable
    {
    
    
        private static final long serialVersionUID = 1582296315990362920L;
		...
        // Preserves singleton property
        private Object readResolve() {
    
    
            return EMPTY_SET;
        }
    }

java.util.Collections.EmptyList

    public static final List EMPTY_LIST = new EmptyList<>();
    private static class EmptyList<E>
        extends AbstractList<E>
		...
        // Preserves singleton property
        private Object readResolve() {
    
    
            return EMPTY_LIST;
        }
    }

java.util.Collections.EmptyMap

public static final Map EMPTY_MAP = new EmptyMap<>();
private static class EmptyMap<K,V>
        extends AbstractMap<K,V>
        implements Serializable
    {
    
    
        private static final long serialVersionUID = 6428348081105594320L;
		...
        // Preserves singleton property
        private Object readResolve() {
    
    
            return EMPTY_MAP;
        }
    }

java.util.Collections.ReverseComparator

As a private inner class, ReverseComparator ensures that it cannot be created elsewhere.
The private construction method: the purpose is to ensure the uniqueness of the singleton object. In fact, it does not matter whether there is a construction method

public class Collections {
    
    
		...
	    private static class ReverseComparator
	        implements Comparator<Comparable<Object>>, Serializable {
    
    
	
	        private static final long serialVersionUID = 7207038068494060240L;
	
	        static final ReverseComparator REVERSE_ORDER
	            = new ReverseComparator();
	
	        public int compare(Comparable<Object> c1, Comparable<Object> c2) {
    
    
	            return c2.compareTo(c1);
	        }
	
	        private Object readResolve() {
    
     return Collections.reverseOrder(); }
	
	        @Override
	        public Comparator<Comparable<Object>> reversed() {
    
    
	            return Comparator.naturalOrder();
	        }
	    }
	    ...
}

java.util.Comparators.NaturalOrderComparator

    /**
     * Compares {@link Comparable} objects in natural order.
     *
     * @see Comparable
     */
    enum NaturalOrderComparator implements Comparator<Comparable<Object>> {
    
    
        INSTANCE;

        @Override
        public int compare(Comparable<Object> c1, Comparable<Object> c2) {
    
    
            return c1.compareTo(c2);
        }

        @Override
        public Comparator<Comparable<Object>> reversed() {
    
    
            return Comparator.reverseOrder();
        }
    }

Guess you like

Origin blog.csdn.net/xiaozhengN/article/details/127350257