Java Description Design Mode (01): Single Case Mode

Keywords: Java Spring Junit jvm JDK

1. Single Case Mode

1. Conceptual illustrations

Singleton Design Mode Definition: Ensure that this class has only one instance and that automatic instantiation provides this object to the system.

2. Sample Code

package com.model.test;
public class Singleton {
    // Recording unique instances using static variables
    private static Singleton singleton = null;
    private Singleton (){}
    public static Singleton getInstance (){
        if (singleton == null){
            singleton = new Singleton() ;
        }
        return singleton ;
    }
    public static void main(String[] args) {
        Singleton singleton1 = Singleton.getInstance() ;
        Singleton singleton2 = Singleton.getInstance() ;
        /**
         * com.model.test.Singleton@15db9742
         * com.model.test.Singleton@15db9742
         */
        System.out.println(singleton1);
        System.out.println(singleton2);
    }
}

Singleton is called a singleton class, and the constructor uses private ly modifiers to ensure that only one instance is generated in the system and is automatically generated.The code above is also known as lazy loading: it's only created when the object is used, meaning you're hungry to cook.

2. Thread Security Issues

There is an obvious thread security issue in the code above, when there are multiple threads requesting object instances, because object creation takes time. Assuming A threads to judge singleton == null, they will enter the object creation process, and if there are several threads at the same time, they will allYou get an object instance, which is called thread security.

1. Synchronization Control Mode

package com.model.test;
public class Singleton {
    // Recording unique instances using static variables
    private static Singleton singleton = null;
    private Singleton (){}
    public static synchronized Singleton getInstance (){
        if (singleton == null){
            singleton = new Singleton() ;
        }
        return singleton ;
    }
}

Doing so can affect system performance

2. Hungry Han Loading

public class Singleton {
    // Recording unique instances using static variables
    private static Singleton singleton = new Singleton();
    private Singleton (){}
    public static Singleton getInstance (){
        return singleton ;
    }
}

Create the object here first and use it directly if necessary.

3. Double Check

public class Singleton {
    // Recording unique instances using static variables
    // volatile ensures that multithreaded processing is not correct until singleton is initialized
    // The value of a variable decorated with volatile will not be cached by the local thread
    // Read and write to this variable are direct operations on shared memory to ensure that multiple threads can properly handle the variable.
    private static volatile Singleton singleton = null ;
    private Singleton (){}
    public static Singleton getInstance (){
        // Enter synchronization zone if instance does not exist
        if (singleton == null){
            // Only the first time will the code inside be executed completely
            synchronized (Singleton.class) {
                if (singleton == null){
                    singleton = new Singleton() ;
                }
            }
        }
        return singleton ;
    }
}

4. Enumeration Method

package com.model.design.base.node01.singleton;
import org.junit.Test;
/**
 * Create an object instance inside a class-level internal class
 */
public class C06_Singleton {
 @Test
 public void test01 (){
 SingletonDemo INSTANCE1 = SingletonDemo.INSTANCE ;
 SingletonDemo INSTANCE2 = SingletonDemo.INSTANCE ;
 System.out.println(INSTANCE1 == INSTANCE2);
 INSTANCE1.info();
 INSTANCE2.info();
 }
}
enum SingletonDemo {
 INSTANCE ;
 public void info (){
 System.out.println("Enumerate implementation singletons");
 }
}

3. Delayed Class Initialization

1. Basic concepts

1) Class-level internal classes
Simply put, class-level internal classes refer to membership internal classes with static modifications.Membership internal classes without a static modification are called object-level internal classes.
Class-level internal classes are equivalent to the static components of their external classes, and there is no dependency between their objects and external class objects, so they can be created directly.Instances of object-level internal classes are bound to external object instances.
Static methods can be defined in class-level internal classes.Only static member methods or member variables in external classes can be referenced in static methods.
A class-level internal class is equivalent to a member of its external class and is loaded only the first time it is used.

2) Multi-threaded default synchronization lock
In multi-threaded development, to solve the concurrency problem, synchronized control is mainly used by adding mutex lock.However, in some cases, the JVM has performed synchronization implicitly, in which case it is not necessary to control synchronization again by itself.These situations include:

1. When data is initialized by a static initializer (on a static field or in a static {} block)
2. When accessing final field
 3. When creating objects before creating threads
 4. When a thread sees the object it will process

2. Implementation

To make thread security easy, you can use a static initializer, which can be secured by a JVM.For example, the previous Hungry Han implementation initializes objects when classes are loaded, and wastes space whether or not needed.
One possible approach is to use a class-level internal class within which to create object instances.This way, as long as you don't use this class-level internal class, you won't create object instances, which allow for both delayed loading and thread security.

public class LazySingleton {
    /**
     * Class-level internal class
     */
    private static class SingletonHolder {
        private static LazySingleton lazySingleton = new LazySingleton() ;
    }
    public static LazySingleton getInstance (){
        return SingletonHolder.lazySingleton ;
    }
    public static void main(String[] args) {
        LazySingleton lazySingleton1 = LazySingleton.getInstance() ;
        LazySingleton lazySingleton2 = LazySingleton.getInstance() ;
        /**
         * com.model.test.LazySingleton@15db9742
         * com.model.test.LazySingleton@15db9742
         */
        System.out.println(lazySingleton1+";;"+lazySingleton2);
    }
}

4. JDK Source Singleton Mode

Runtime singleton implementation source code.

1. Case Demonstration

/**
 * JDK Single Case Pattern Analysis
 */
public class C07_Singleton {
 public static void main(String[] args) {
 Runtime runtime1 = Runtime.getRuntime() ;
 Runtime runtime2 = Runtime.getRuntime() ;
 /*
 * 1229416514
 * 1229416514
 */
 System.out.println(runtime1.hashCode());
 System.out.println(runtime2.hashCode());
 }
}

2. Source Code Analysis

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

A singleton pattern based on the Hungry Han pattern.

5. Application in Spring Framework

1. Create test classes

public class UserBean {
}

2. Spring Profile

<!-- Singleton Bean -->
<bean id="user" 
class="com.model.design.spring.node01.singleton.UserBean" />

3. Test Read Bean Objects

package com.model.design.spring.node01.singleton;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
 * Spring Singleton pattern in framework
 */
public class S01_Singleton {
    @Test
    public void test01 (){
        ApplicationContext context01 = new ClassPathXmlApplicationContext("/spring/spring-context.xml");
        ApplicationContext context02 = new ClassPathXmlApplicationContext("/spring/spring-context.xml");
        UserBean user01 = (UserBean)context01.getBean("user") ;
        UserBean user02 = (UserBean)context01.getBean("user") ;
        UserBean user03 = (UserBean)context02.getBean("user") ;
        // com.model.design.spring.node01.singleton.UserBean@364841
        System.out.println(user01);
        // com.model.design.spring.node01.singleton.UserBean@364841
        System.out.println(user02);
        // com.model.design.spring.node01.singleton.UserBean@c4711c
        System.out.println(user03);
    }
}

conclusion
The main difference between the Spring singleton pattern and the pure singleton design pattern
Although the same class loader is used to load two application contexts, the instances of UserBean are different.That is, the single object in the Spring framework is application-based.

6. Summary of Single Case Mode

1. Notes

Singleton pattern considerations and details
 1) The singleton mode ensures that there is only one object in the system memory, which saves system resources. For some objects that need to be destroyed frequently, using the singleton mode can improve system performance.
2) When you want to instantiate a single class, you must remember to use the appropriate method to get the object, not the new Object().
3) Scenarios used by the singleton mode: objects that need to be created and destroyed frequently, objects that take too much time to create, or objects that consume too much resources (that is, heavyweight objects), but are often used.

2. Advantages and disadvantages

Advantage:
1. Singleton mode only creates one instance of an object, reducing memory consumption
 2. Set up global access points to optimize access to shared resources
 Disadvantages:
1. Without interfaces, it is difficult to extend
 2. Adverse to testing
 3. Conflict with the principle of single responsibility

7. Source code address

GitHub Address: Know a smile
https://github.com/cicadasmile/model-arithmetic-parent
 Code Cloud Address: Know a smile
https://gitee.com/cicadasmile/model-arithmetic-parent

Posted by yogibear333 on Fri, 23 Aug 2019 17:38:34 -0700