All you want to know about the Java singleton design pattern is here!

There are actually many issues that programmers need to consider when writing code:

  1. Availability (completely achieve business goals)

  2. Robustness (programs can guarantee normal operation in various environments and various operations)

  3. Reusability (code can be called by other modules to achieve different purposes, here is the idea of ​​decoupling to a certain extent)

  4. Scalability (code design is flexible enough to adapt to as many businesses as possible)

  5. performance

  6. Memory footprint (In my understanding, performance and memory footprint are often dilemma, performance improvement often means more memory usage. For example, dynamic array ArrayList will be expanded by 1.5 times in order to avoid frequent expansion, so that data is at a lower cost increase.)

Based on the above problems and the continuous design of the code, the predecessors have found the corresponding optimal solutions to some common and general problems (note that this is the way to solve the problem rather than the answer to the problem, it means more A kind of thought, and our code is the carrier of this thought) From this, a design pattern is derived: the design pattern-the singleton pattern.

01 Singleton definition

A singleton is a single instance. In Java, this means that there can be only one object of a class.

Why do you need a singleton? Think about it with me. In real life, it is impossible for us to build a shopping mall to meet the shopping needs of one person. And a mall can perform the function of selling things for many people, and that person only needs to enter the mall to use the function of selling things like other people.

So we found that all of us did not achieve the same goal. In many cases, what we need is what it can do, not itself. I will not create a mall for shopping, I will use the function of selling things in the same mall like everyone else.

The same is true in java, we use an object method, we need:

1. Create this object first

2. Call this object method

3. Discard the object

It’s okay for one person to use it, so what if there are tens of millions of people? Does that have to create objects millions of times? But the real need for millions of us to achieve our goals is not this object, but the function of this object.

Summary: When a functional class is shared by multiple objects, in order to avoid wasting memory resources and frequently creating objects. This class needs to be singletonized.

02 Singleton design process

Constructor privatization

In order to ensure that there is only one object in memory forever, do not let other classes create objects. We need to set the permission to create, only the class itself has permission to create objects.

private SingleTon(){}

Internally created objects

At this time, the problem is that when only the class itself can create objects, where should we create it? Let's review the class structure: construction methods, code blocks, methods, and attributes.

  1. Construction method: The construction method has been privatized, even if your internal method is a new object. But sorry that the outside world cannot call the execution construction method, this new cannot be executed

  2. Code block: The code block can be executed when the class is initialized, but the problem is that there is no basket to connect the egg, and the outside world cannot get the address to find the object created in this code block

  3. Method: This is a question of whether there is a chicken or an egg first. This method is not used to create external objects.

  4. Attributes: This seems to be the last straw, as if objects can also be created in attributes

private SingleTon(){}public SingleTon singleTon=new SingleTon();

Create and get

But here comes the problem. You create an object, the properties of the object create the object, and the properties of the object create the properties of the object. The system will execute such a nesting doll.

Objects in the heap memory continue to nest attributes in, and the construction method stack opened by the first object in the stack memory has not been executed yet, a new construction method stack has to be opened, so that the method stacks in the heap memory continue to accumulate to form a stack Memory escape error.

We need to tell the computer that this object only needs one, where can only one object of a class exist in the static area.

We need to add a static modifier to this attribute. One is to make the initialization of other classes complete to avoid the doll-like creation of objects, and the other is that static variables can be obtained by the outside world.

But there is another problem at this time:

SingleTon.singleTon=null

If a user tampered with this unique object, it would not be feasible. We need to make a simple package, leaving only a back door for you to come and fetch it.

private SingleTon (){}private static SingleTon singleTon=new SingleTon();public static SingleTon getSingleTon(){   return singleTon; }

But please don't forget that in the java world we can open up: we can get private attributes through reflection for tampering, so we need to add a final modification to make the variable itself completely unchangeable.

method one:

private SingleTon (){}private static final SingleTon singleTon=new SingleTon();public static SingleTon getSingleTon(){   return singleTon; }

This is one of the singleton methods, this code has a problem. When my business is executed, this object may not be used, but this object is cold in memory after initialization; and if there are tens of millions of singletons in a system, when the system is initialized, all singleton objects are initialized. The pressure of the server is hard to imagine.

So we can set up a mechanism and create it when we need it. At this time, everyone asked me a question, what will happen if it is multi-threaded?

Way two:

private SingleTon(){}private static SingleTon  singleTon;public static  SingleTon getSingleTon(){   if (singleTon==null){        singleTon= new SingleTon();    } }

If there are two threads AB: Normally, A judges that no A is created, A is created and B is judged to be used directly

But what if B finds that the object has not been created when A is created

This is a security problem caused by atomicity that does not reach multi-thread concurrency

So in order to prevent the problems caused by multi-threading, we should add a lock to the method. During the locking period, other threads cannot use the method.

Way three:

//防止高并发private SingleTon(){}private static SingleTon  singleTon;public static  synchronized SingleTon getSingleTon(){   if (singleTon==null){        SingleTon= new singleTon();    } }

But there is another problem: this method will perform many other things internally, and these things multi-threaded environment will not cause problems.

At this time, other threads will wait unnecessarily for a long time, so we should lock locally (we should try our best to avoid a thread holding the lock for a long time)

Way four:

private SingleTon(){}private static SingleTon singleTon;public static SingleTon getSingleTon(){ if (singleTon==null){ synchronized(Singleton.class){ //We will lock this class immediately after the judgment //In order to prevent the lock before Someone has created the object first, and then make another judgment if(singleTon == null) {singleTon = new Singleton()}}}}

At this time, there is actually one last question:

single=new Singleton(); This line of code has executed more than one step, divided into three steps

  1. Allocate memory space

  2. Call the constructor, load the object

  3. Assign address to variable

At this time, the jvm itself has a feature of instruction rearrangement, that is, these three instructions may be shuffled and executed. In order to improve performance, compilers and processors often rearrange the order of execution of the established code.

At this time, everyone think about it with me: if 1 is executed, 3 is executed first. Before executing 3 and preparing to execute 2, another thread judges that this variable has an address reference! I just used the non-empty one. When I used it, I found that it was an empty shell, which would cause a null pointer exception.

So we need to make jvm not to execute instruction rearrangement. Java provides the volatile keyword volatile to modify variables. There are two characteristics: 1. Prohibit instruction rearrangement 2. Ensure variable visibility The first feature can help us solve the instruction rearrangement problem:

Way Five:

private SingleTon(){}private static volatile SingleTon  singleTon;public static   SingleTon getSingleTon(){   if (singleTon==null){       synchronized(Singleton.class){           if(singleTon == null){                singleTon= new Singleton()            }        }    } }

to sum up:

Method 1: Create an object in the attribute, static modification prevents multiple execution of the construction method fianl and private modification to prevent modification, leave a static method to get

Method 2: Add a lazy loading mechanism, and when needed, if the object is not created again

Method 3: In order to prevent high concurrency, lock the method

Method 4: Local lock is only used for the assignment process. Method 5 Volatile modified variable prevents instruction rearrangement

This article is original

Author: YANG

Guess you like

Origin blog.51cto.com/13409950/2541778