Simple design pattern has series - singleton

Note : This article comes from bloggers: chloneda

Foreword

Simple design pattern has family, as far as possible easy to understand, step by step manner, so that we truly understand the essence of design patterns!

Singleton knowledge

Before you begin to explain singletons, first look at the knowledge Singleton pattern.

Singleton Pattern definition: to ensure a class to instantiate only one instance, and provide a global access point, this example provides the whole system.

Mode type: create a class mode

FIG singleton class:
singleton

Singleton pattern can be simply summarized as three elements:

  • Private constructor.
  • Provide private, static, point to refer to the current instance.
  • Provide public, static method that is global access point to return to this instance.

Nature singletons: control the number of instances.

The main problem Singleton pattern

Our problem singleton pattern is often used mainly involved are:

  • How to ensure that only one instance of a class?
  • How to ensure singleton thread-safe in a multithreaded environment?
  • How to prevent damage to the reflective Singleton pattern?
  • How to ensure the uniqueness of the singleton instance deserialization and serialization process?

Examples of single-mode

Singleton common are hungry Chinese-style, lazy, double-check the lock, static inner classes manner, enumerating, the main discussion here singleton in a multithreaded environment.

Hungry Chinese-style

This hungry man, single cases are more common, we look at it is how to achieve!

package com.chloneda.jutils.test;

/**
 * @Created by chloneda
 * @Description: 饿汉式单例模式
 */
public class Singleton {

    private static Singleton instance = new Singleton();

    private Singleton (){}

    public static Singleton getInstance() {
        return instance;
    }
}

Example starving single thread itself is safe, but it is by way of the space for time, immediately when the class is instantiated loading Singleton object even without using the user, each subsequent call to getInstance () method of the time, not determine whether it needs to instantiate, thereby saving time. But in some cases required lazy loading object instance, for this case, so with lazy singleton type.

Lazy style

We look at the implementation lazy man Singleton pattern.

package com.chloneda.jutils.test;

/**
 * @Created by chloneda
 * @Description: 懒汉式单例模式
 */
public class Singleton {

    private static Singleton instance;

    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

This is our common lazy man singleton! We did not find? This lazy man singleton in a multithreaded environment, there is a thread safety problem! How does it lead to multi-thread safety problems?

To facilitate understanding of the issues we Singleton pattern can easily arise in a multithreaded environment, using the following direct picture of the way, look at the picture:
singleton-thread

Known problem lazy man singleton pattern of multi-threaded environment from the chart, right!

For multi-threaded safety defect exists above singleton, others say it is not easy to solve, directly getInstance plus Java keyword method on the synchronized , that is.

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

But you can not forget, in Java, each statement is executed will take time, plus the synchronized keyword underlying need to perform more statements, and required each time through getInstance () Gets an instance method, the efficiency is very bottom , let alone implementation in multi-threaded high-concurrency, so this must be improved.

Double check locks

For the above performance issues singleton lazy man, I double checked the lock by modifying a single case.

package com.chloneda.jutils.test;

/**
 * @Created by chloneda
 * @Description: 双重检验锁单例模式
 */
public class Singleton {

    private static Singleton instance;

    private Singleton (){}

    public static Singleton getInstance() {
        if (instance == null) { // 双重检测机制
            synchronized (Singleton.class) { // 同步锁
                if (instance == null) { // 双重检测机制
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

The above double lock wording examination of a single embodiment, is not higher than the efficiency of lazy single embodiment, because each need getInstance acquiring example method, only the first instance of the instance plus synchronization lock, after entering the subsequent multi-thread method, directly into the outer layer if (instance == null) Analyzing statement examples that instance is not empty, the instance directly returned instance.

Although Singleton double check the lock mechanism of the above adds a certain security, improve efficiency, but this double check the lock Singleton is also flawed because it does not take into account the JVM compiler command rearrangement.

1, what is the command reordering
such as in a simple java instance = new Singleton (), as will be compiled into JVM instruction translator.

memory = allocate();    //1:分配对象的内存空间 
ctorInstance(memory);  //2:初始化对象 
instance = memory;     //3:设置instance指向刚分配的内存地址

However, these instructions are not immutable sequence, there may be optimized through the JVM and the CPU, an instruction rearrangement in the following order.

memory = allocate();    //1:分配对象的内存空间 
instance = memory;      //3:设置instance指向刚分配的内存地址 
ctorInstance(memory);  //2:初始化对象

2, influence

High concurrency, thread A execution instance = new Singleton (); upon completion of the above steps 1, 3, 2 ready to go, i.e. the object instance initialization has not been completed, but this time the instance is no longer pointing to null.

Thread B seize this moment to CPU resources when performing if (instance == null), the results returned will be false,

To return a no instance of the object initialization is complete.

3, the solution
of how to solve this problem? Very simple, you can modify an object instance using the keyword volatile, optimization as follows:

Double check the lock improvement

package com.chloneda.jutils.test;

/**
 * @Created by chloneda
 * @Description: 单例模式使用双重检验锁方式实现,优点:延迟初始化、性能优化、线程安全
 */
public class Singleton {

    private volatile static Singleton instance;

    private Singleton (){}

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

The volatile modifier role here is to prevent the variable access command before and after the rearrangement, thus ensuring the order of execution of instructions.

I.e., instruction execution order is strictly according to the above steps 2, 3 is performed, thereby ensuring that the object will not be an intermediate state.

But the above embodiment mode, the single lock improved version of the double check is also problematic, because it can not solve the reflection mode embodiment of the single-destructive. I will be set forth in a static inner class singleton mode.

Static inner classes

Before looking at a static inner classes Singleton, let us first look at two static inner classes of knowledge.

  • Static inner classes to load a class whose inner classes will not be loaded simultaneously.
  • A class is loaded, if and only if one of its members as static static fields, constructors, static methods are invoked will be loaded.

We look at a static inner class tests to verify the above two viewpoints.

package com.chloneda.jutils.test;

/**
 * @Created by chloneda
 * @Description: 静态内部类测试类
 */
public class OuterClassTest {

    private OuterClassTest() {}

    static {
        System.out.println("1、我是外部类静态模块...");
    }

    // 静态内部类
    private static final class StaticInnerTest {
        private static OuterClassTest oct = new OuterClassTest();

        static {
            System.out.println("2、我是静态内部类的静态模块... " + oct);
        }

        static void staticInnerMethod() {
            System.out.println("3、静态内部类方法模块... " + oct);
        }
    }

    public static void main(String[] args) {
        OuterClassTest oct = new OuterClassTest(); // 此刻内部类不会被加载
        System.out.println("===========分割线===========");
        OuterClassTest.StaticInnerTest.staticInnerMethod(); // 调用内部类的静态方法
    }
}

Output follows.

1、我是外部类静态模块...
=========分割线=========
2、我是静态内部类的静态模块... com.chloneda.jutils.test.OuterClassTest@b1bc7ed
3、静态内部类的方法模块... com.chloneda.jutils.test.OuterClassTest@b1bc7ed

From the running results, verify that is correct!

Due to the nature of static inner classes, it will only be loaded when it is first referenced, so it can ensure its thread safety.

Whereby writing can be drawn inside the static singleton class.

Static inner classes

package com.chloneda.jutils.test;

/**
 * @Created by chloneda
 * @Description:
 *  单例模式使用静态内部类方式实现,优点:实现代码简洁、延迟初始化、线程安全
 */
public class Singleton {

    private static final class SingletonHolder {
        private static Singleton INSTANCE = new Singleton();
    }

    private Singleton(){}

    public static Singleton getInstance(){
        return SingletonHolder.INSTANCE;
    }
}

The wording of a single case, can not access the external static inner classes SingletonHolder, only when calls Singleton.getInstance () method, to get singleton object INSTANCE.

Further embodiments of the single static inner class getInstance () method does not use the synchronized (initialized when the object of use, space-saving, to lazy load) keywords, improve the efficiency, taking into account the lazy memory optimization mode, and mode starving security.

However, this single case is also a problem! This approach requires two classes to do this, that, although the lazy load the object static inner classes, but class Class object its external and internal static class or will be created, but also unable to prevent the reflection of a single case destructive ( many written singleton have this common problem ), which can not guarantee the uniqueness of the object.

We destructive static inner classes through the following test class test reflection.

/**
 * @Created by chloneda
 * @Description: 反射破坏静态内部类单例模式的测试类
 */
public class SingletonReflectTest {
    public static void main(String[] args) {
        //创建第一个实例
        Singleton instance1 = Singleton.getInstance();

        //通过反射创建第二个实例
        Singleton instance2 = null;
        try {
            Class<Singleton> clazz = Singleton.class;
            Constructor<Singleton> cons = clazz.getDeclaredConstructor();
            cons.setAccessible(true);
            instance2 = cons.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }

        //检查两个实例的hash值
        System.out.println("Instance1 hashCode: " + instance1.hashCode());
        System.out.println("Instance2 hashCode: " + instance2.hashCode());
    }
}

The output results are as follows.

Instance1 hashCode: 186370029
Instance2 hashCode: 2094548358

As can be seen from the output results acquired by reflecting the constructor and calling setAccessible (true) can call the private constructor, and whereby Instance1 Instance2 two different objects.

Static inner classes to improve

This reflection on how to prevent a single case of damage to it? We can modify the constructor throws an exception when it was asked to create a second instance.

Internal static type modified as follows.

package com.chloneda.jutils.test;

/**
 * @Created by chloneda
 * @Description: 防止反射破坏静态内部类单例模式
 */
public class Singleton {

    private static boolean initialized = false;

    private static final class SingletonHolder {
        private static Singleton INSTANCE = new Singleton();
    }

    private Singleton() {
        synchronized (Singleton.class) {
            if (initialized == false) {
                initialized = !initialized;
            } else {
                throw new RuntimeException("单例模式禁止二次创建,防止反射!");
            }
        }
    }

    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
    
}

We also used a SingletonReflectTest test class test, output results are as follows.

java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at com.chloneda.jutils.test.SingletonReflectTest.main(Singleton.java:46)
Caused by: java.lang.RuntimeException: 单例模式禁止二次创建,防止反射!
    at com.chloneda.jutils.test.Singleton.<init>(Singleton.java:24)
    ... 5 more
Instance1 hashCode: 1053782781
Exception in thread "main" java.lang.NullPointerException
    at com.chloneda.jutils.test.SingletonReflectTest.main(Singleton.java:53)

Therefore, we prevent the reflection destructive embodiments by modifying a single constructor.

But a single case in this way there is a problem! What's the problem? That is, after serialization and de-serialization can not continue to maintain a single case ( a lot of writing singleton also have this common problem ).

We let a single case of damage to prevent reflection above the static inner classes implement Serializable interface.

public class Singleton implements Serializable 

And serialization and deserialization tested by the test class.

/**
 * @Created by chloneda
 * @Description: 序列化破坏静态内部类单例模式的测试类
 */
pubic class SingletonSerializableTest {
    public static void main(String[] args) {
        try {
            Singleton instance1 = Singleton.getInstance();
            ObjectOutput out = null;

            out = new ObjectOutputStream(new FileOutputStream("Singleton.ser"));
            out.writeObject(instance1);
            out.close();

            //从文件中反序列化一个Singleton对象
            ObjectInput in = new ObjectInputStream(new FileInputStream("Singleton.ser"));
            Singleton instance2 = (Singleton) in.readObject();
            in.close();

            System.out.println("instance1 hashCode: " + instance1.hashCode());
            System.out.println("instance2 hashCode: " + instance2.hashCode());

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

The output results are as follows.

instance1 hashCode: 240650537
instance2 hashCode: 1566502717

From the results, it is clear that the same is not a singleton object!

How then to solve this problem?

Static inner classes further improvements

We can achieve readResolve () method, which replaces the object read from the stream, in the process did not ensure that the serialization and de-serialization of people can create a new instance.

Internal static type can be improved version of a single embodiment, can effectively prevent damage of the sequence and reflective!

package com.chloneda.jutils.test;

import java.io.*;

/**
 * @Created by chloneda
 * @Description: 可以防止序列化及反射破坏的静态内部类单例模式
 */
public class Singleton implements Serializable {

    private static boolean initialized = false;

    private static final class SingletonHolder {
        private static Singleton INSTANCE = new Singleton();
    }

    private Singleton() {
        synchronized (Singleton.class) {
            if (initialized == false) {
                initialized = !initialized;
            } else {
                throw new RuntimeException("单例模式禁止二次创建,防止反射!");
            }
        }
    }

    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }

    private Object readResolve() {
        return getInstance();
    }
}

We then above SingletonSerializableTest test class test results.

The output results are as follows.

instance1 hashCode: 240650537
instance2 hashCode: 240650537

In this case it shows the object in a single embodiment serialization and deserialization is the same.

Actually, the problem above a hungry man style, lazy, double-checking locks and internal static class Singleton emerged, can be resolved through enumeration singleton, which is the "Effective Java" recommended wording.

Enumerated

We know that in java enum class is only in JDK5, therefore enumeration singleton for most people is relatively unknown, to give an example of it!

Enumeration singleton very simple to achieve.

public enum Singleton {
    INSTANCE;
}

On three lines, it is very simple. Then it easier for everyone to understand, I use the following example to analyze what enumeration singleton it!

package com.chloneda.jutils.test;

/**
 * @Created by chloneda
 * @Description: 单例类
 */
public class Singleton{}

/**
 * 枚举型单例
 */
public enum SingletonEnum {
    INSTANCE;
    private Singleton singleton = null;

    private SingletonEnum() {
        singleton = new Singleton();
    }

    public Singleton getInstance() {
        return singleton;
    }
}

The above enumeration singleton, decompile you will get the following code.

public final class SingletonEnum extends java.lang.Enum<SingletonEnum> {
    public static final SingletonEnum INSTANCE;
    public static SingletonEnum[] values();
    public static SingletonEnum valueOf(String);
    public Singleton getSingleton();
    static {};
}

After processing the above code (remove the package name only, to facilitate reading)!

Can be found enumeration singleton-relevant attributes are static keyword modification, a closer look or final modification of an ordinary class, but inherits from java.lang.Enum enumeration class only. That this enumeration singleton is processed through a compiler, which is syntactic sugar JDK5 provided (Syntactic Sugar), the so-called syntactic sugar means some kind of syntax to add in computer language, this grammatical function of language does not affect just cheated on compilers, programmers can be more convenient we use.

Enumeration singleton is inherently thread-safe, because the JVM class loading mechanism sake, do not start here discussed, you can refer to the relevant information!

Enumerated Example reflections single

Let's look at why the problem of enumeration singleton reflection can be prevented?

In fact, JDK5, Java virtual machine to do a special class enumeration process, that JVM will prevent reflection acquiring private constructor enumeration class.

We use this enumeration singleton as an example.

public enum Singleton {
    INSTANCE;

    Singleton() {
    }
}

Continue to use the reflection code above SingletonReflectTest to be tested, a first example of a statement to create first SingletonReflectTest into this class.

    //创建第一个实例
    Singleton instance1 = Singleton.INSTANCE;

After running output results are as follows.

java.lang.NoSuchMethodException: com.chloneda.jutils.test.Singleton.<init>()
    at java.lang.Class.getConstructor0(Class.java:3082)
    at java.lang.Class.getDeclaredConstructor(Class.java:2178)
    at com.chloneda.jutils.test.SingletonReflectTest.main(SingletonReflectTest.java:18)
Instance1 hashCode: 1929600551
Exception in thread "main" java.lang.NullPointerException
    at com.chloneda.jutils.test.SingletonReflectTest.main(SingletonReflectTest.java:27)

Direct reported abnormal, that enumeration singleton can be the perfect solution to the problem of reflection.

Enumerated Example deserialization problems single

The following further in-depth look at why the enumeration will meet deserialization problem

Java specification says enumeration each enumeration type very defined in the JVM is unique, so the serialization and de-serialization of enumerated types, Java made a special provision.

In Java serialization only when the name attribute is an enumeration object to the output results, deserialized when it is based on the name to java.lang.Enum by the valueOf () method to find the enumeration object.

To the above public enum SingletonEnum enumeration example, the sequence of the time only the name of the output INSTANCE, deserialization time again by this name, search for enumerated types, so examples of the deserialized and also before serialized instances of the same object.

We tested it by testing the class, we let enumeration singleton SingletonEnum implement Serializable interface.

public enum SingletonEnum implements Serializable

Re-use of the test sequence based SingletonSerializableTest test, the output results are as follows.

instance1 hashCode: 1674896058
instance2 hashCode: 1674896058

That enumeration singleton can solve the problems caused by anti-serialization.

In summary, the enumeration singleton can effectively solve the problem of thread safety, reflection, deserialization brings!

However, you do not proud, enumeration singleton is also a problem, is that it can not be lazy loaded because enumeration singleton instance of an object is in static code block to initialize static blocks, that is not awoken ah !

Intermission

Having said that singleton pattern, know the pros and cons of each singleton pattern, so when we use, we have to make a choice based on the actual situation, because we can not achieve a singleton can meet all situations.

Let's take a look at the actual application scenario Singleton pattern of it!

Single mode practical embodiment

Life singleton

There are many scenes on our computer applications to Singleton, it may often see, but we do not recognize, such as the following example.

  • Windows Task Manager (Task Manager) is a typical singleton. Have you tried to open two windows task manager do?

  • windows are typical single trash Application Example. During the entire operation of the system, it maintains the Recycle Bin has been only one instance.

  • Website counter, are generally single-case model to achieve, otherwise difficult to synchronize.

  • Application Log application, generally realized what a singleton pattern, which is generally due to the shared log file remains open, because only one instance to operate, otherwise good additional content.

  • Read the configuration objects Web applications, generally use single-mode cases, this is because the configuration file is a shared resource.

  • Designing Multithreaded thread pool is generally a single embodiment mode, since the thread pool to facilitate control of the thread pool.

Of course, there are many applications singleton pattern, I hope you can find Oh!

JDK in singleton

java.lang.Runtime

Runtime class encapsulates the Java runtime environment. Every java program actually started a JVM process, each JVM process is this corresponds to a Runtime instance, which is instantiated by the JVM for. Each application has a Java Runtime class instance, enables applications to run environment connected therewith.

Because Java is a single process, so in a JVM, examples of Runtime should be only one, so it should be implemented using a single case.

We take a look java.lang.Runtime singleton pattern implementation.

public class Runtime {
    private static Runtime currentRuntime = new Runtime();

    public static Runtime getRuntime() {
        return currentRuntime;
    }

    private Runtime() {}
}

Did not see a single case model used here is a hungry man single-case model, that is, when the class for the first time when they were loaded classloader, instance is created out when the caller per call, do not We need to determine whether the instance has been initialized, the space for typical program time.

As used herein, the starving single embodiment mode, is undoubtedly a very suitable!

java.awt.Toolkit

Toolkit is the GUI class, and the difference is RunTime Toolkit uses a lazy man singleton, because they do not need to create good, then create it as long as the first time really used.

Let's look at the code Toolkit class.

public abstract class Toolkit {

    private static Toolkit toolkit;
    
    public static synchronized Toolkit getDefaultToolkit() {
        if (toolkit == null) {
            java.security.AccessController.doPrivileged(
                    new java.security.PrivilegedAction<Void>() {
                public Void run() {
                    Class<?> cls = null;
                    String nm = System.getProperty("awt.toolkit");
                    try {
                        cls = Class.forName(nm);
                    } catch (ClassNotFoundException e) {
                        ClassLoader cl = ClassLoader.getSystemClassLoader();
                        if (cl != null) {
                            try {
                                cls = cl.loadClass(nm);
                            } catch (final ClassNotFoundException ignored) {
                                throw new AWTError("Toolkit not found: " + nm);
                            }
                        }
                    }
                    try {
                        if (cls != null) {
                            toolkit = (Toolkit)cls.newInstance();
                            if (GraphicsEnvironment.isHeadless()) {
                                toolkit = new HeadlessToolkit(toolkit);
                            }
                        }
                    } catch (final InstantiationException ignored) {
                        throw new AWTError("Could not instantiate Toolkit: " + nm);
                    } catch (final IllegalAccessException ignored) {
                        throw new AWTError("Could not access Toolkit: " + nm);
                    }
                    return null;
                }
            });
            loadAssistiveTechnologies();
        }
        return toolkit;
    }
    
}

Observe the above code you will find Toolkit is an abstract class that can not be instantiated itself, and instead create a new instance of the class is loaded by reflection.

Single idler embodiment mode, and does not create a first time instance, the JVM startup speed increase, a typical time for space program, but also reflects the idea of ​​loading delay.

Also, note that the thread-safety issues lazy man singletons, on the Internet there are many versions, have their own advantages, we appropriate choice now!

Example of a single frame

  • Example Mybatis the single mode: The ErrorContext and LogFactory.
  • Spring Framework Singleton: by way of a single embodiment registry single embodiment mode implementations, such as getBeans () method AbstractBeanFactory abstract class.

summary

This article is a bit long, but managed to clear the Singleton pattern, hey, my brain cells!

Guess you like

Origin www.cnblogs.com/chloneda/p/pattern-singleton.html