Design pattern learning 04 (Java implementation) - singleton pattern

Kang Xiaozhuang 2021-06-23 20:35:30
design pattern learning java implementation


Write it at the front

  • Take notes on learning design patterns
  • Improve the flexible use of design patterns

Study address

https://www.bilibili.com/vide...

https://www.bilibili.com/vide...

Reference article

http://c.biancheng.net/view/1...

Project source code
https://gitee.com/zhuang-kang/DesignPattern

4, Creator mode

The main focus of creative patterns is “ How to create an object ?”, Its main feature is “ Separate the creation and use of objects ”.

This can reduce the coupling of the system , Users don't need to pay attention to the details of object creation .

The creation mode is divided into two types :

  • The singleton pattern
  • Factory method model
  • Abstract engineering patterns
  • Archetypal model
  • Builder pattern

5, The singleton pattern

5.1 The definition and characteristics of singleton pattern

Single case (Singleton) Definition of pattern : A class has only one instance , And this class can create a pattern of this instance by itself . for example ,Windows Only one task manager can be opened in , This can avoid the waste of memory resources caused by opening multiple task manager windows , Or there are errors such as inconsistent display contents of each window .

In computer system , also Windows The recycle bin 、 File system in operating system 、 Thread pool in multithreading 、 Graphics card driver object 、 Background processing services for printers 、 The log object of the application 、 Connection pool for database 、 Counters for websites 、Web Applied configuration objects 、 Dialog boxes in the application 、 The cache in the system is often designed as a single example .

Singleton mode is also widely used in real life , For example, the company CEO、 Department managers, etc. are all singleton models .J2EE Standard ServletgContext and ServletContextConfig、Spring Framework application ApplicationContext、 The connection pool in the database is also singleton mode .

The singleton pattern is as follows 3 Characteristics :

  1. A singleton class has only one instance object ;
  2. The singleton object must be created by the singleton class itself ;
  3. The singleton class provides a global access point to access the singleton .

Advantages of singleton mode

  • The singleton mode ensures that there is only one instance in memory , Reduced memory overhead .
  • It can avoid multiple occupation of resources .
  • Singleton mode sets global access points , Can optimize and share access to resources .

Disadvantages of singleton mode :

  • Singleton mode generally has no interface , Extend the difficult . If you want to expand , In addition to modifying the original code , There is no second way , Against the principle of opening and closing .
  • In concurrent testing , Singleton mode is not good for code debugging . In the course of debugging , If the code in the singleton is not finished , You can't simulate a new object .
  • The function code of singleton pattern is usually written in a class , If the function design is unreasonable , It is easy to violate the principle of single responsibility .

5.2 The structure and implementation of singleton pattern

5.2.1 The structure of singleton pattern

  1. Singleton class : A class that contains an instance and can create it by itself .
  2. Access class : Classes that use singletons .

5.2 Code implementation

There are two types of singleton design patterns :

 Hungry Chinese style : Class loading causes the singleton object to be created
Slacker type : Class loading does not cause the singleton object to be created , It's created when the object is first used 

Hungry Chinese style ( Static variables )

package com.zhuang.singleton.type1;
/**
* @Classname SingletonTest01
* @Description Hungry Chinese style ( Static variables )
* @Date 2021/3/17 9:26
* @Created by dell
*/
public class SingletonTest01 {
public static void main(String[] args) {
Singleton instance = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
// Judge whether it is a singleton
System.out.println(instance == instance2);
System.out.println("intstance Hash value of " + instance.hashCode());
System.out.println("intstance2 Hash value of " + instance2.hashCode());
}
}
class Singleton {
//1. Constructor privatization , External energy new、
private Singleton() {
}
// Create an object instance inside this class
private final static Singleton instance = new Singleton();
// Provide a public static method to the outside
public static Singleton getInstance() {
return instance;
}
}

<font color='red'> explain :</font>

 This method declares... In the member position Singleton Static variables of type , And create Singleton Class object instance.instance Objects are created as classes load . If the object is large enough , And if you don't use it all the time, it will cause a waste of memory .

Static code block

package com.zhuang.singleton.type2;
/**
* @Classname SingletonTest02
* @Description Static code block
* @Date 2021/3/17 9:35
* @Created by dell
*/
public class SingletonTest02 {
public static void main(String[] args) {
Singleton2 instance = Singleton2.getInstance();
Singleton2 instance2 = Singleton2.getInstance();
// Judge whether it is a singleton
System.out.println(instance == instance2);
System.out.println("intstance Hash value of " + instance.hashCode());
System.out.println("intstance2 Hash value of " + instance2.hashCode());
}
}
class Singleton2 {
//1. Constructor privatization , External energy new、
private Singleton2() {
}
// Create an object instance inside this class
private static Singleton2 instance;
/*
Creating objects in static code blocks
*/
static {
instance = new Singleton2();
}
// Provide a public static method to the outside
public static Singleton2 getInstance() {
return instance;
}
}

<font color='red'> explain :</font>

 This method declares... In the member position Singleton Static variables of type , Objects are created in static blocks of code , Also created for loading classes . So with the starving way 1 Basically the same ,** Of course, this method also has the problem of memory waste .**

Slacker type Thread unsafe

package com.zhuang.singleton.type3;
/**
* @Classname SingletonTest03
* @Description Slacker type Thread unsafe
* @Date 2021/3/17 9:39
* @Created by dell
*/
public class SingletonTest03 {
public static void main(String[] args) {
System.out.println(" Slacker type , Thread unsafe !!!");
Singleton instance = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
// Judge whether it is a singleton
System.out.println(instance == instance2);
System.out.println("intstance Hash value of " + instance.hashCode());
System.out.println("intstance2 Hash value of " + instance2.hashCode());
}
}
class Singleton {
private static Singleton instance;
private Singleton() {
}
// Provides a static public method When this method is used , To create instance
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}

<font color='red'> explain :</font>

 From the above code, we can see that this way is declared in the member position Singleton Static variables of type , There is no object assignment operation , So when was the assignment made ? When calling getInstance() Method to get Singleton Class Singleton Class object , This achieves the effect of lazy loading . however , If it's a multithreaded environment , There will be thread safety issues .

Slacker type ( Thread safety , Synchronization method )

package com.zhuang.singleton.type4;
/**
* @Classname SingletonTest04
* @Description Slacker type ( Thread safety , Synchronization method )
* @Date 2021/3/17 9:46
* @Created by dell
*/
public class SingletonTest04 {
public static void main(String[] args) {
System.out.println(" Slacker type , Thread safety !!!");
Singleton instance = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
// Judge whether it is a singleton
System.out.println(instance == instance2);
System.out.println("intstance Hash value of " + instance.hashCode());
System.out.println("intstance2 Hash value of " + instance2.hashCode());
}
}
class Singleton {
private static Singleton instance;
private Singleton() {
}
// Provides a static public method , Add the synchronization code , Solving thread safety problems
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}

<font color='red'> explain :</font>

 This method also realizes the lazy loading effect , At the same time, it solves the problem of thread safety . But in getInstance() Method added synchronized keyword , As a result, the execution effect of this method is very low . We can see from the above code that , It's initialization instance Thread safety issues only occur when the thread is safe , Once the initialization is complete, it doesn't exist .

Slacker type ( Thread safety , Synchronization code block )

package com.zhuang.singleton.type5;
/**
* @Classname SingletonTest05
* @Description Slacker type ( Thread safety , Synchronization code block )
* @Date 2021/3/17 9:50
* @Created by dell
*/
public class SingletonTest05 {
public static void main(String[] args) {
System.out.println(" Slacker type , Thread safety !, Synchronization code block ");
Singleton instance = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
// Judge whether it is a singleton
System.out.println(instance == instance2);
System.out.println("intstance Hash value of " + instance.hashCode());
System.out.println("intstance2 Hash value of " + instance2.hashCode());
}
}
class Singleton {
private static Singleton instance;
private Singleton() {
}
// Provides a static public method , Add the synchronization code , Solving thread safety problems
public static synchronized Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
instance = new Singleton();
}
}
return instance;
}
}

Double check lock mode is a very good single instance implementation mode , Solved the single case 、 performance 、 Thread safety problem , The double detection lock mode above looks perfect , In fact, there are problems , In the case of multithreading , There may be a null pointer problem , The reason for the problem is JVM When instantiating an object, it will perform optimization and instruction reordering operations .

To solve the problem of null pointer exception caused by double check lock mode , Just use volatile keyword , volatile Keywords ensure visibility and order .

package com.zhuang.singleton.type6;
/**
* @Classname SingletonTest06
* @Description Double check , Recommended
* @Date 2021/3/17 9:54
* @Created by dell
*/
public class SingletonTest06 {
public static void main(String[] args) {
System.out.println(" Slacker type , Double check , Recommended ");
Singleton instance = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
// Judge whether it is a singleton
System.out.println(instance == instance2);
System.out.println("intstance Hash value of " + instance.hashCode());
System.out.println("intstance2 Hash value of " + instance2.hashCode());
}
}
class Singleton {
private static volatile Singleton instance;
private Singleton() {
}
// Provides a static public method , Add double check code , Add the synchronization code , Solve the problem of lazy loading
// Ensure efficiency . Recommended
public static synchronized Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
instance = new Singleton();
}
}
return instance;
}
}

<font color="red"> Summary :</font>

add to volatile The double check lock mode after the keyword is a better single instance implementation mode , It can ensure thread safety without performance problems in the case of multithreading .

Static inner class implements singleton pattern !

package com.zhuang.singleton.type7;
/**
* @Classname SingletonTest07
* @Description Static inner class implements singleton pattern !
* @Date 2021/3/17 9:59
* @Created by dell
*/
public class SingletonTest07 {
public static void main(String[] args) {
System.out.println(" Static inner class implements singleton pattern ");
Singleton instance = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
// Judge whether it is a singleton
System.out.println(instance == instance2);
System.out.println("intstance Hash value of " + instance.hashCode());
System.out.println("intstance2 Hash value of " + instance2.hashCode());
}
}
class Singleton {
private static Singleton instance;
private Singleton() {
}
// Write a static inner class , There is a static property in this class ,Singleton
public static class SingletonInstance {
private static final Singleton INSTANCE = new Singleton();
}
// Provides a static public method , Go straight back to SingletonInstance.INSTANCE;
public static synchronized Singleton getInstance() {
return SingletonInstance.INSTANCE;
}
}

<font color='red'> explain :</font>

 First load Singleton Class does not initialize INSTANCE, Only the first call getInstance, Virtual machine loading SingletonHolder

And initialization INSTANCE, This not only ensures thread safety , Also can guarantee Singleton Class uniqueness .

<font color="red"> Summary :</font>

 Static inner class singleton mode is an excellent singleton mode , It is a single instance mode commonly used in open source projects . Without any locks , It ensures the security of multithreading , And there's no performance impact or space waste .

Enumeration to achieve singleton mode

package com.zhuang.singleton.type8;
/**
* @Classname SingletonTest08
* @Description Enumeration to achieve singleton mode
* @Date 2021/3/17 10:06
* @Created by dell
*/
public class SingletonTest08 {
public static void main(String[] args) {
System.out.println(" Enumeration to achieve singleton mode , Recommended ");
Singleton instance = Singleton.INSTANCE;
Singleton instance2 = Singleton.INSTANCE;
System.out.println(instance == instance2);
// Judge whether it is a singleton
System.out.println(instance == instance2);
System.out.println("intstance Hash value of " + instance.hashCode());
System.out.println("intstance2 Hash value of " + instance2.hashCode());
}
}
/*
enumeration
*/
enum Singleton {
INSTANCE;// attribute
public void method() {
System.out.println("method() Method is called ...");
}
}

explain :

 Enumeration belongs to the evil Chinese way .

5.3 Application scenario of singleton mode

  • Some classes that need to be created frequently , Using singletons can reduce the memory pressure of the system , Reduce GC.
  • When a class only needs to generate one object , Like a monitor in a class 、 Everyone's ID number, etc .
  • Some classes occupy more resources when creating instances , Or instantiation takes a long time , And often use .
  • A class needs to be instantiated frequently , When the created objects are destroyed frequently , Such as multithreaded thread pool 、 Network connection pool, etc .
  • Objects that frequently access databases or files .
  • For some control hardware level operations , Or from the system point of view, it should be a single control logic operation , If there are multiple instances , Then the system will be completely out of order .
  • When objects need to be shared . Because singleton mode allows only one object to be created , Sharing this object saves memory , And speed up object access . Such as Web Configuration object in 、 Database connection pool, etc .

5.4 The problem is

Break singleton mode :

Make the singleton class defined above (Singleton) You can create multiple objects , Except enumeration . There are two ways , They are serialization and reflection .

  • Serialization deserialization

    Singleton class :

    public class Singleton implements Serializable {
    // Private constructor
    private Singleton() {}
    private static class SingletonHolder {
    private static final Singleton INSTANCE = new Singleton();
    }
    // Provide a static method to get the object
    public static Singleton getInstance() {
    return SingletonHolder.INSTANCE;
    }
    }

Test class :

public class Test {
public static void main(String[] args) throws Exception {
// Write objects to the file
//writeObject2File();
// Reading objects from a file
Singleton s1 = readObjectFromFile();
Singleton s2 = readObjectFromFile();
// Determine whether two deserialized objects are the same object
System.out.println(s1 == s2);
}
private static Singleton readObjectFromFile() throws Exception {
// Create object input stream object
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("C:\\Users\\dell\\Desktop\\a.txt"));
// The first read Singleton object
Singleton instance = (Singleton) ois.readObject();
return instance;
}
public static void writeObject2File() throws Exception {
// obtain Singleton Class object
Singleton instance = Singleton.getInstance();
// Create an object output stream
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C:\\Users\\dell\\Desktop\\a.txt"));
// take instance Object is written to a file
oos.writeObject(instance);
}
}
The result of the above code is false, Indicates that serialization and deserialization have broken the singleton design pattern .
  • Reflection

    Singleton class :

    public class Singleton {
    // Private constructor
    private Singleton() {}
    private static volatile Singleton instance;
    // Provide a static method to get the object
    public static Singleton getInstance() {
    if(instance != null) {
    return instance;
    }
    synchronized (Singleton.class) {
    if(instance != null) {
    return instance;
    }
    instance = new Singleton();
    return instance;
    }
    }
    }

Test class :

public class Test {
public static void main(String[] args) throws Exception {
// obtain Singleton Class bytecode object
Class clazz = Singleton.class;
// obtain Singleton Class's private nonparametric construction method object
Constructor constructor = clazz.getDeclaredConstructor();
// Cancel access check
constructor.setAccessible(true);
// establish Singleton Class object s1
Singleton s1 = (Singleton) constructor.newInstance();
// establish Singleton Class object s2
Singleton s2 = (Singleton) constructor.newInstance();
// Judge the two created by reflection Singleton Whether the object is the same object
System.out.println(s1 == s2);
}
}

The result of the above code is false, Indicates that serialization and deserialization have broken the singleton design pattern

<font color="red"> Be careful :</font> Enumeration does not cause these two problems .

Problem solving

  • serialize 、 The solution to breaking singleton pattern in reverse sequence mode

    stay Singleton Class readResolve() Method , Called by reflection on deserialization , If this method is defined , Return the value of this method , If there is no definition , Return to the new new Out object .

    Singleton class :

    public class Singleton implements Serializable {
    // Private constructor
    private Singleton() {}
    private static class SingletonHolder {
    private static final Singleton INSTANCE = new Singleton();
    }
    // Provide a static method to get the object
    public static Singleton getInstance() {
    return SingletonHolder.INSTANCE;
    }
    /**
    * The following is to solve the problem of serialization and deserialization cracking singleton mode
    */
    private Object readResolve() {
    return SingletonHolder.INSTANCE;
    }
    }

The source code parsing :

ObjectInputStream class

public final Object readObject() throws IOException, ClassNotFoundException{
...
// if nested read, passHandle contains handle of enclosing object
int outerHandle = passHandle;
try {
Object obj = readObject0(false);// Focus on readObject0 Method
.....
}
private Object readObject0(boolean unshared) throws IOException {
...
try {
switch (tc) {
...
case TC_OBJECT:
return checkResolve(readOrdinaryObject(unshared));// Focus on readOrdinaryObject Method
...
}
} finally {
depth--;
bin.setBlockDataMode(oldMode);
}
}
private Object readOrdinaryObject(boolean unshared) throws IOException {
...
//isInstantiable return true, perform desc.newInstance(), Create a new singleton class by reflection ,
obj = desc.isInstantiable() ? desc.newInstance() : null;
...
// stay Singleton Class readResolve After the method desc.hasReadResolveMethod() The result of method execution is true
if (obj != null && handles.lookupException(passHandle) == null && desc.hasReadResolveMethod()) {
// Call by reflection Singleton Class readResolve Method , Assign return value to rep Variable
// So many times ObjectInputStream Class readObject Method , And then we call what we define readResolve Method , So it returns the same object .
Object rep = desc.invokeReadResolve(obj);
...
}
return obj;
}
  • The solution to cracking singletons by reflection

    public class Singleton {
    // Private constructor
    private Singleton() {
    /*
    Reflection cracking singleton mode needs to add code
    */
    if(instance != null) {
    throw new RuntimeException();
    }
    }
    private static volatile Singleton instance;
    // Provide a static method to get the object
    public static Singleton getInstance() {
    if(instance != null) {
    return instance;
    }
    synchronized (Singleton.class) {
    if(instance != null) {
    return instance;
    }
    instance = new Singleton();
    return instance;
    }
    }
    }

<font color="red"> explain :</font>

 This is a better way to understand . When a constructor is called by reflection to create , Direct throw anomaly . Do not run this operation .

5.5 JDK The source code parsing -Runtime class

Runtime Class is the singleton design pattern used .

  1. Check which singleton mode is used through the source code

    public class Runtime {
    private static Runtime currentRuntime = new Runtime();
    /**
    * 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;
    }
    /** Don't let anyone else instantiate this class */
    private Runtime() {}
    ...
    }

As you can see from the source code above Runtime Class uses the evil Chinese style ( Static attribute ) Method to realize singleton mode .

  1. Use Runtime Methods in class

    public class RuntimeDemo {
    public static void main(String[] args) throws IOException {
    // obtain Runtime Class object
    Runtime runtime = Runtime.getRuntime();
    // return Java Total memory in the virtual machine .
    System.out.println(runtime.totalMemory());
    // return Java The maximum amount of memory a virtual machine tries to use .
    System.out.println(runtime.maxMemory());
    // Create a new process to execute the specified string command , Returns the process object
    Process process = runtime.exec("ipconfig");
    // Get the result of command execution , Get... Through the input stream
    InputStream inputStream = process.getInputStream();
    byte[] arr = new byte[1024 * 1024* 100];
    int b = inputStream.read(arr);
    System.out.println(new String(arr,0,b,"gbk"));
    }
    }

At the end

  • If my article is useful to you , Please order me a , Thank you for your !
  • There is a problem , Welcome to the comment area !
版权声明
本文为[Kang Xiaozhuang]所创,转载请带上原文链接,感谢
https://javamana.com/2021/06/20210623203408156v.html

  1. 【计算机网络 12(1),尚学堂马士兵Java视频教程
  2. 【程序猿历程,史上最全的Java面试题集锦在这里
  3. 【程序猿历程(1),Javaweb视频教程百度云
  4. Notes on MySQL 45 lectures (1-7)
  5. [computer network 12 (1), Shang Xuetang Ma soldier java video tutorial
  6. The most complete collection of Java interview questions in history is here
  7. [process of program ape (1), JavaWeb video tutorial, baidu cloud
  8. Notes on MySQL 45 lectures (1-7)
  9. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
  10. Refined spring boot 03: spring boot configuration files and configuration management, and reading configuration files in three ways
  11. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
  12. Refined spring boot 03: spring boot configuration files and configuration management, and reading configuration files in three ways
  13. 【递归,Java传智播客笔记
  14. [recursion, Java intelligence podcast notes
  15. [adhere to painting for 386 days] the beginning of spring of 24 solar terms
  16. K8S系列第八篇(Service、EndPoints以及高可用kubeadm部署)
  17. K8s Series Part 8 (service, endpoints and high availability kubeadm deployment)
  18. 【重识 HTML (3),350道Java面试真题分享
  19. 【重识 HTML (2),Java并发编程必会的多线程你竟然还不会
  20. 【重识 HTML (1),二本Java小菜鸟4面字节跳动被秒成渣渣
  21. [re recognize HTML (3) and share 350 real Java interview questions
  22. [re recognize HTML (2). Multithreading is a must for Java Concurrent Programming. How dare you not
  23. [re recognize HTML (1), two Java rookies' 4-sided bytes beat and become slag in seconds
  24. 造轮子系列之RPC 1:如何从零开始开发RPC框架
  25. RPC 1: how to develop RPC framework from scratch
  26. 造轮子系列之RPC 1:如何从零开始开发RPC框架
  27. RPC 1: how to develop RPC framework from scratch
  28. 一次性捋清楚吧,对乱糟糟的,Spring事务扩展机制
  29. 一文彻底弄懂如何选择抽象类还是接口,连续四年百度Java岗必问面试题
  30. Redis常用命令
  31. 一双拖鞋引发的血案,狂神说Java系列笔记
  32. 一、mysql基础安装
  33. 一位程序员的独白:尽管我一生坎坷,Java框架面试基础
  34. Clear it all at once. For the messy, spring transaction extension mechanism
  35. A thorough understanding of how to choose abstract classes or interfaces, baidu Java post must ask interview questions for four consecutive years
  36. Redis common commands
  37. A pair of slippers triggered the murder, crazy God said java series notes
  38. 1、 MySQL basic installation
  39. Monologue of a programmer: despite my ups and downs in my life, Java framework is the foundation of interview
  40. 【大厂面试】三面三问Spring循环依赖,请一定要把这篇看完(建议收藏)
  41. 一线互联网企业中,springboot入门项目
  42. 一篇文带你入门SSM框架Spring开发,帮你快速拿Offer
  43. 【面试资料】Java全集、微服务、大数据、数据结构与算法、机器学习知识最全总结,283页pdf
  44. 【leetcode刷题】24.数组中重复的数字——Java版
  45. 【leetcode刷题】23.对称二叉树——Java版
  46. 【leetcode刷题】22.二叉树的中序遍历——Java版
  47. 【leetcode刷题】21.三数之和——Java版
  48. 【leetcode刷题】20.最长回文子串——Java版
  49. 【leetcode刷题】19.回文链表——Java版
  50. 【leetcode刷题】18.反转链表——Java版
  51. 【leetcode刷题】17.相交链表——Java&python版
  52. 【leetcode刷题】16.环形链表——Java版
  53. 【leetcode刷题】15.汉明距离——Java版
  54. 【leetcode刷题】14.找到所有数组中消失的数字——Java版
  55. 【leetcode刷题】13.比特位计数——Java版
  56. oracle控制用户权限命令
  57. 三年Java开发,继阿里,鲁班二期Java架构师
  58. Oracle必须要启动的服务
  59. 万字长文!深入剖析HashMap,Java基础笔试题大全带答案
  60. 一问Kafka就心慌?我却凭着这份,图灵学院vip课程百度云