Perfect solution to the lazy thread safety problem in the singleton design pattern

  • 2020-05-26 08:30:42
  • OfStack

First, write a singleton:


public class SingleDemo { 
  private static SingleDemo s = null; 
  private SingleDemo(){} 
  public static SingleDemo getInstance(){ 
    if(s == null){ 
      s = new SingleDemo(); 
    } 
    return s; 
  } 
} 

Write a test class:


public class ThreadDemo3 { 
   
  public static void main(String[] args) { 
    SingleDemo s1 = SingleDemo.getInstance(); 
    SingleDemo s2 = SingleDemo.getInstance(); 
    System.out.println(s2 == s2); 
  } 
} 

Run result 1 is true, it is no problem under single thread, let's write a multi-thread to access the singleton


public class ThreadTest implements Runnable { 
  // Store singleton object, use Set This is to avoid storing duplicate elements  
  public Set<SingleDemo> singles = new HashSet<SingleDemo>(); 
  @Override 
  public void run() { 
    // Access to the singleton  
    SingleDemo s = SingleDemo.getInstance(); 
    // Add a singleton  
    singles.add(s); 
  } 
} 

Using multithreaded concurrent access singletons:


public class ThreadDemo3 { 
   
  public static void main(String[] args) { 
//   SingleDemo s1 = SingleDemo.getInstance(); 
//   SingleDemo s2 = SingleDemo.getInstance(); 
//   System.out.println(s2 == s2); 
    ThreadTest t = new ThreadTest(); 
    new Thread(t).start(); 
    new Thread(t).start(); 
    new Thread(t).start(); 
    new Thread(t).start(); 
    new Thread(t).start(); 
    new Thread(t).start(); 
    new Thread(t).start(); 
    new Thread(t).start(); 
    System.out.println(t.singles); 
  } 
} 


The results are as follows:
[com.persagy.thread.SingleDemo@1bc4459, com.persagy.thread.SingleDemo@150bd4d]

or

[com.persagy.thread.SingleDemo@12b6651]

It shows that there is a thread access security problem, not 1 must be the same one instance

How do you solve the thread safety problem?

Of course we use the synchronous lock mechanism

The following improved singleton:


public class SingleDemo {
	private static SingleDemo s = null;
	private SingleDemo(){}
	public static synchronized SingleDemo getInstance(){
		if(s == null){
			s = new SingleDemo();
		}
		return s;
	}
}

The thread safety problem was resolved when the synchronization function was added

Run multiple times to get the same instance, there will not be two instances

[com.persagy.thread.SingleDemo@12b6651]

However, in the case of concurrent access by multiple threads, each thread needs to judge the lock every time it gets an instance, which is inefficient. In order to improve the efficiency, I added the method of dual judgment to solve the problem of efficiency

The code is as follows:


public class SingleDemo {
	private static SingleDemo s = null;
	private SingleDemo(){}
	public static SingleDemo getInstance(){
		/* If the first 1 Four threads get the instance object of the singleton, 
		 *  The later thread does not need to go into the synchronized block to retrieve the instance */
		if(s == null){
			// The lock used for synchronizing code blocks is the singleton's bytecode file object, and only this lock can be used 
			synchronized(SingleDemo.class){
				if(s == null){
					s = new SingleDemo();
				}
			}
		}
		return s;
	}
}

In this way to solve the lazy thread safety problem, also improve the efficiency, but in the actual development or to use the hungry han more, after all, this code is more, more tedious.


Related articles: