Java design patterns described in (01): Singleton

A, singleton

1, illustrating the concept of

Defined singleton design pattern: this ensures that only one instance of the class, and the system automatically provide instantiation of the object.

2, sample code

package com.model.test;
public class Singleton {
    // 使用静态变量记录唯一实例
    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 called Singleton constructor private modifier, to ensure the system can produce an example, and automatically generated. The above code is also known as the lazy man's load: Only when using the object was to create the means to do just hungry to eat.

Second, the security thread

In the above code is present in an obvious security thread, when a plurality of threads to request an object instance, because it takes time to create an object, assuming the thread coming Analyzing A singleton == null, will enter the object creation process, then if at the same time over a few threads, then they will get an object instance, this is the so-called thread-safety issues.

1, synchronous control mode

package com.model.test;
public class Singleton {
    // 使用静态变量记录唯一实例
    private static Singleton singleton = null;
    private Singleton (){}
    public static synchronized Singleton getInstance (){
        if (singleton == null){
            singleton = new Singleton() ;
        }
        return singleton ;
    }
}

Such action will affect system performance

2, starving type load

public class Singleton {
    // 使用静态变量记录唯一实例
    private static Singleton singleton = new Singleton();
    private Singleton (){}
    public static Singleton getInstance (){
        return singleton ;
    }
}

Create objects out of here first, there is the need for direct use;

3, double-checked

public class Singleton {
    // 使用静态变量记录唯一实例
    // volatile可以确保当singleton被初始化后,多线程才可以正确处理
    // 被volatile修饰的变量的值,将不会被本地线程缓存
    // 对该变量读写都是直接操作共享内存,确保多个线程能正确的处理该变量。
    private static volatile Singleton singleton = null ;
    private Singleton (){}
    public static Singleton getInstance (){
        // 如果实例不存在,则进入同步区
        if (singleton == null){
            // 只有第一次才会彻底执行这里面的代码
            synchronized (Singleton.class) {
                if (singleton == null){
                    singleton = new Singleton() ;
                }
            }
        }
        return singleton ;
    }
}

4, enumerating

package com.model.design.base.node01.singleton;
import org.junit.Test;
/**
 * 类级内部类里面创建对象实例
 */
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("枚举方式实现单例");
 }
}

Third, delay class initialization

1, the basic concept

1), class-level inner classes
  Simply put, class-level inner classes means that there is static modification of members of the inner class type. If there is no static modification of members of the inner class type it is called object-level inner classes.
  Class-level static component of its inner classes corresponding to the outer class, whose objects with dependencies between external object does not exist, it can be created directly. While examples of class internal object level, is bound in an external object instance.
  Class-level internal class can be defined in a static method. Only members can refer to a static method or field outside of class in a static method.
  Class-level members of its inner classes equivalent to the outer class, and only the first time was only to be used will be loaded.

2), multi-thread synchronization lock by default
  in multi-threaded development in order to solve concurrency issues, mainly through the use of synchronized to add mutex synchronization control. However, in some cases, JVM has been implicitly perform synchronization, these cases do not come to synchronize their own control. These include:

  1.由静态初始化器(在静态字段上或static{}块中的初始化器)初始化数据时
  2.访问final字段时
  3.在创建线程之前创建对象时
  4.线程可以看见它将要处理的对象时

2, implementation

To very simple to implement thread safe, you can use a static initializer way, it can be made to ensure the safety of the JVM thread. For example, in front of a hungry man type implementation, at the time the class is loaded on to initialize the object, regardless of whether there is a certain waste of space.
One possible way is to use class-level internal class to create an object instance of this class level inner classes inside. As a result, they do not use this class to class inner class, it does not create an object instance, to simultaneously achieve lazy loading and thread-safe.

public class LazySingleton {
    /**
     * 类级内部类
     */
    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);
    }
}

Four, JDK source singleton

Runtime singleton realize source.

1, case presentations

/**
 * JDK 单例模式分析
 */
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() {}
}

Singleton starving mode based implementation.

Five, Spring Framework application

1, create a test class

public class UserBean {
}

2, Spring configuration file

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

3, the test subject reads Bean

package com.model.design.spring.node01.singleton;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
 * Spring框架中单例模式
 */
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
Spring singleton main difference with pure single design pattern
although the same class loader to load the application context two, but the examples are not the same UserBean. I.e. singleton object Spring Framework is based on the application.

VI summarizes singleton

1 Notes

单例模式注意事项和细节说明
1) 单例模式保证了 系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统性能。
2) 当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是使用new Object() 的方式。
3) 单例模式使用的场景:需要频繁的进行创建和销毁的对象、创建对象时耗时过多或耗费资源过多(即:重量级对象),但又经常用到的对象。

2, advantages and disadvantages

优点:
1、单例模式只会创建一个对象实例,减少内存消耗
2、设置全局访问点,优化共享资源的访问
缺点:
1、没有接口,很难扩展
2、不利于测试
3、与单一职责原则冲突

Seven, the source address

GitHub地址:知了一笑
https://github.com/cicadasmile/model-arithmetic-parent
码云地址:知了一笑
https://gitee.com/cicadasmile/model-arithmetic-parent


Guess you like

Origin www.cnblogs.com/cicada-smile/p/11204316.html