Singleton design double check lock This method adopts double lock mechanism, which is safe and can maintain high performance in the case of multiple threads. But there are pros and cons

Double check lock code

public class DoubleLock { private static DoubleLock doubleLock; private DoubleLock(){ } public static DoubleLock getInstance(){ if (doubleLock == null){ synchronized (DoubleLock.class){ if (doubleLock == null){ doubleLock = new DoubleLock(); } } } return doubleLock; }}Copy the code

advantages

Safe and high-performance in multi-threaded situations, the first if judgment prevents wasted performance by other useless threads competing for the lock, and the second if judgment blocks threads other than the first one that acquired the object lock.

Instead of nullating A second time, let’s consider thread A, where thread B blocks on the lock acquisition step, where THREAD A acquires the lock — instantiates the object —- release the lock, and thread B acquires the lock — instantiates the object, which violates the intent of our singleton pattern.

The problem

The theory behind double-checked locking is perfect. Unfortunately, the reality is quite different. The problem with double-checked locking is that there is no guarantee it will run smoothly on single-processor or multi-processor computers.

The problem of double-checked locking failure is not due to implementation bugs in the JVM, but to the Java platform memory model. The memory model allows so-called “out-of-order writes” and is a major reason these idioms fail.

singleton = new Singleton();
Copy the code

This statement is a non-atomic operation that actually takes three steps.

  • 1. Allocate memory for Singleton
  • 2. Call the Singleton constructor to initialize a member variable;
  • 3. The singleton object will point to the allocated memory space (singleton is not null);

Virtual machine instruction reorder — >

The virtual machine may switch locations for the above three steps when executing the command and may end up at 132. This may cause problems when multithreading is fetched without initialization after allocating memory and modifying Pointers.

Singleton = new Singleton(); In code, exactly these three steps are reordered to 1, 3, 2,

Then the Singleton object is not null after step 3, but the singleton object is not initialized completely before Step 2. At this point, thread B executes getInstance(). If the singleton is not null in the first step, the partially initialized Singleton object is directly returned.

To solve

If a field is declared volatile, the Java thread memory model ensures that all threads see the variable with the same value and disallows instruction reordering

So using the volatile keyword prevents instruction reordering and avoids this problem. Volatile makes singleton = new singleton (); The statement must be executed according to step 123 of the split above.

Another question

The singleton pattern is not perfectly safe and can be broken by reflection; only enumeration-safe classes are safe.

Part reference links: blog.csdn.net/qq646040754…