Implementation of Singleton Pattern Singleton

1. Non-lazy mode

//Singleton with static factory
class SingletonExample {

    private static final SingletonExample singleton = new SingletonExample();

    private SingletonExample() {
    }

    public static final SingletonExample getInstance() {
        return singleton;
    }
}

 

2. Implementation of lazy mode (low efficiency)

class SingletonExample {
    private static SingletonExample singleton;

    private SingletonExample() {
    }

    public synchronized SingletonExample getInstance() {
        if (singleton == null) {
            singleton = new SingletonExample();
        }
        return singleton;
    }
}

 

3. Implementation of efficient lazy mode

class SingletonExample {
    private static SingletonExample singleton;

    private SingletonExample() throws Exception {
    }

    public static SingletonExample getInstance() {
        if (singleton == null) {    // the calls arriving after singleton is created will not enter this branch, this line is not synchronized, so they won’t lock each other.
            synchronized (SingletonExample.class) {    // for the first call, we still have to lock it
                if (singleton == null) {
                    try {
                        singleton = new SingletonExample();
                    } catch (Exception e) {

                    }
                }
            }
        }
        return singleton;
    }
}

 

4. All of the above designs are extremely vulnerable in two cases:

One, Java Reflection attack, such as:

public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        Class<?> clazz = Class.forName("test.SingletonExample");
        Constructor<?> constructor = clazz.getDeclaredConstructor();
        constructor.setAccessible(true);
        SingletonExample singleton1 = (SingletonExample)constructor.newInstance();
        SingletonExample singleton2 = (SingletonExample)constructor.newInstance();
}

Second, if the singleton needs to be serialized, the singleton will be destroyed during deserialization.

 

5. The recommended solution is to use enum instead of class to write singleton

public enum SingletonExample {
    INSTANCE;
   
    public static SingletonExample getInstance() {
        return INSTANCE;
    }
}

According to the conclusion of Effective Java, the introduction of this method uses the special serialization mechanism provided by JDK for enum, which can effectively prevent multiple instantiations in the face of complex serialization and deserialization. In addition, the constructor of enum must be private, and its constructor is only visible to internal members. External classes cannot see this constructor at runtime (much stricter than private), so conventional reflection methods cannot be used to convert It is set to public.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326543455&siteId=291194637