In the standard 23 design patterns, the single case design pattern is more common in the application. However, in the general introduction of this mode of teaching materials, most of them are not combined with multithreading technology as a reference, which results in the use of multithreading technology in the singleton mode, there will be some unexpected situation, such code if in the production environment anomalies, can have disastrous consequences.
1. Load Now/"A Hungry man mode"
What is load now? The immediate load is also known as the "a Hungry Man mode", where the object is created when the class is used, and the common implementation is to instantiate it directly.
Load Now/"A Hungry Man mode" is the instance that was created before calling the method, and look at the implementation code.
/** * This code is loaded immediately, the disadvantage is that there is no other instance variable * because the getinstance () method is not synchronized, a non-thread-safe section may occur */public class MyObject { private static MyObject m Yobject = new MyObject (); Private MyObject () {} public static MyObject getinstance () { return MyObject; }}
public class MyThread extends Thread { @Override public void Run () { System.out.println ( Myobject.getinstance (). Hashcode ());} }
public class Run {public static void Main (string[] args) throws ParseException { MyThread t1 = new MyThread ();
mythread t2 = new MyThread (); MyThread t3 = new MyThread (); T1.start (); T2.start (); T3.start (); }}
1032010069 1032010069 1032010069 |
The hashcode that the console prints is the same value, stating that the object is the same, and that an immediate-loading singleton design pattern is implemented.
2. Lazy loading/"lazy mode"
What is deferred loading? Lazy loading, also known as lazy mode, is the instance that is created when the Get () method is called, and the common implementation is to instantiate the new in the Get () method.
Lazy Load/Lazy mode is the instance that was created when the method was called. Although only one instance is taken in a thread, multiple instances are taken out in a multithreaded environment.
public class MyObject { private static MyObject MyObject; Private MyObject () {} public static MyObject getinstance () { if (MyObject = = null) { //impersonation do some preparatory work before creating the object try { thread.sleep; } catch (Interruptedexception e) { e.printstacktrace (); } MyObject = new MyObject (); } return myObject;} }
Custom threads and run-similar, the result
658705244 580835623 1791140146 |
The console prints 3 types of hashcode, stating that 3 objects were created, not Singleton, which is the "wrong singleton pattern". How to solve it? Look at the solution first.
2.1. Deferred loading/"lazy mode" solution
(1) Declaration synchronized keyword
Now that multiple threads can enter the human getinstance () method at the same time, you only need to declare the SYNCHRONIZED keyword to the getinstance () method.
public class MyObject { private static MyObject MyObject; Private MyObject () {} /** * This kind of synchronized lock method is very inefficient, although it is running synchronously, but each call to getinstance (), the object must be locked * And the next thread wants to get the object, it must wait for the last thread to release the lock before it can continue execution. * /public synchronized static MyObject getinstance () { if (MyObject = = null) { //impersonation do some preparatory work before creating 2 objects try { thread.sleep; } catch (Interruptedexception e) { e.printstacktrace (); } MyObject = new MyObject (); } return myObject;} }
Custom threads and run-similar, the result
1791140146 1791140146 1791140146 |
2.2. Try synchronizing the code block
The synchronous method is to lock the whole method, which is not disadvantageous to the operation efficiency. Is it possible to change to a synchronous block of code? First look at an example of a less efficient
public class MyObject {/ * * holds a private static instance that is protected from reference and is assigned null here to enable lazy loading */ private static MyObject MyObject = null; Private MyObject () {} public static MyObject getinstance () { try {/ * * This notation is equivalent to: * public synchronized Static MyObject getinstance () is very inefficient * */ synchronized (myobject.class) { if (MyObject = = null) {
//simulation To do some preparatory work before creating the object Thread.Sleep (); MyObject = new MyObject ();}} } catch (Interruptedexception e) { e.printstacktrace (); } return myObject;} }
Custom threads and run-similar, the result
658705244 658705244 658705244 |
Synchronous code blocks can be synchronized for some important code, while others do not need to be synchronized. In this way, efficiency can be greatly improved at run time.
Using the DCL dual detection lock mechanism to implement, continue to modify this code:
public Class MyObject {/* holds a private static instance that is protected from reference and is assigned null here to enable lazy loading */private static MyObject MyObject = null; Private MyObject () {}//uses a dual detection mechanism to solve the problem, ensuring asynchronous execution without the need for synchronous code, and ensuring that the effect of a singleton is static MyObject getinstance () {try { if (MyObject = = null) {//simulate doing some preparatory work before creating the object Thread.Sleep (3000); Separate synchronization for some important code!!! Synchronized (Myobject.class) {//If this is not the case, the same instance object cannot be reached in multi-threaded situations!!! if (MyObject = = null) {MyObject = new myObject (); }}}} catch (Interruptedexception e) {e.printstacktrace (); } return myObject; }}
1791140146 1791140146 1791140146 |
Using the double check lock feature, successfully solved the problem of multi-threading in "lazy Mode". DCL is also a solution used by most multithreading in conjunction with a singleton pattern.
Java multithreaded Programming 6--single-case mode and multi-threading--a single-case pattern design 1