concept

  • Creation pattern
  • There is only one class created by the singleton method in the current process

scenario

  • Database thread pool
  • Spring Bean (singleton)

Singleton subdivision

SequenceDiagram QUESTION ->> A: Simplest? A: What if there are too many classes and the service starts too slowly? A ->> Q: 02, lazy - thread unsafe Q -) A: This thread is unsafe? -->> Q: 03, lazy -- thread safety (synchronization) Q --) A: Method using sychronized, affecting performance? -->> Q: 04, lazy -- thread safety (double lock check) Q -) A: Can use JUC to achieve? A ->> Q: 05, lazy - thread safety (CAS high concurrency) Q -) A: No locking ability? Q -) Q -) A: Can enumeration classes work? A -->> Q: 07, enumeration -- thread safety

Hungry — Thread safety

  • The program starts, instantiating the object
  • Multiple classes cause slow startup
  • Maybe some classes just need to be instantiated at use
public class HungrySafe{
    // Static constant
    private static final HungrySafe hungrySafe=new HungrySafe();
    
    // Method 2:
    private static final HungrySafe hungrySafe;
    static{
        hungrySafe=new HungrySafe();
    }
    public static HungrySafe getInstance(a){
        returnhungrySafe; }}/ / test
public class HungrySafeTest {
    public static void main(String[] args) { HungrySafe map=HungrySafe.getInstance(); HungrySafe map2=HungrySafe.getInstance(); System.out.println(map); System.out.println(map2); }}Copy the code

02, Lazy (thread unsafe)

  • Privatize constructors
  • The first time you use it, create an instance
  • Multithreading creates multiple instances (unsafe)
public class LazyUnSafe {
    private static LazyUnSafe lazyUnSafe;
    private LazyUnSafe(a){}public static LazyUnSafe getInstance(a){
        if(lazyUnSafe! =null) {return lazyUnSafe;
        }
        lazyUnSafe= new LazyUnSafe();
        returnlazyUnSafe; }}/ / test
class LazyUnSafeTest {
    public static void main(String[] args) throws InterruptedException {
        Thread t=new Thread(()->{
            LazyUnSafe lazyUnSafe=LazyUnSafe.getInstance();
            System.out.println(lazyUnSafe);
        });
        t.start();
        //t.join(); // Test thread safety hereLazyUnSafe lazyUnSafe=LazyUnSafe.getInstance(); System.out.println(lazyUnSafe); }}Copy the code

03, Lazy – Synchronization (thread-safe)

  • Method to add the synchoronized keyword (sync lock)
  • All access requires lock holding (acquiring/releasing locks)
  • Not recommended
public class LazySafeSync {
    private static LazySafeSync lazySafeSync=new LazySafeSync();
    private LazySafeSync(a){}
    public static synchronized LazySafeSync getInstance(a){
        if(lazySafeSync! =null) {return lazySafeSync;
        }
        returnlazySafeSync; }}/ / test
class LazySafeSyncTest {
    public static void main(String[] args) {
        Thread t=newThread(()->{ LazySafeSync lazySafeSync=LazySafeSync.getInstance(); System.out.println(lazySafeSync); }); t.start(); LazySafeSync lazySafeSync=LazySafeSync.getInstance(); System.out.println(lazySafeSync); }}Copy the code

04, Lazy – double lock check (thread safety)

  • The synchoronized keyword is not used in the method
  • Locks class objects
  • Improved performance (Contrast 03)
public class LazySafeSyncX {
    private static volatile LazySafeSyncX lazyUnSafe;
    private LazySafeSyncX(a){}
    public static LazySafeSyncX getInstance(a){
        if(lazyUnSafe! =null) {return lazyUnSafe;
        }
        synchronized (LazySafeSync.class){
            if(lazyUnSafe==null){
                lazyUnSafe=newLazySafeSyncX(); }}returnlazyUnSafe; }}/ / test
class LazySafeSyncXTest {
    public static void main(String[] args) {
        Thread t=newThread(()->{ LazySafeSyncX lazySafeSyncX=LazySafeSyncX.getInstance(); System.out.println(lazySafeSyncX); }); t.start(); LazySafeSyncX lazySafeSyncX=LazySafeSyncX.getInstance(); System.out.println(lazySafeSyncX); }}Copy the code

05, Lazy -CAS (Thread Safety)

  • CAS algorithm, AtomicReference atom class
  • Support high concurrency, no thread switching and blocking
  • Intense competition leads to endless waiting –> infinite loop (CPU performance)
public class LazySafeAtomic {
    private static final AtomicReference<LazySafeAtomic> reference=new AtomicReference<>();
    private LazySafeAtomic(a){}public static LazySafeAtomic getInstance(a){
        for(;;) { LazySafeAtomic lazySafeAtomic=reference.get();if(lazySafeAtomic! =null) {return lazySafeAtomic;
            }
            reference.compareAndSet(null.new LazySafeAtomic());
            returnreference.get(); }}}/ / test
class LazySafeAtomicTest {
    public static void main(String[] args) {
        Thread t=newThread(()->{ LazySafeAtomic lazySafeAtomic=LazySafeAtomic.getInstance(); System.out.println(lazySafeAtomic); }); t.start(); LazySafeAtomic lazySafeAtomic=LazySafeAtomic.getInstance(); System.out.println(lazySafeAtomic); }}Copy the code

06. Lazy – Inner Class (thread-safe)

  • Static inner classes guarantee the creation of unique instances
  • Lazy loading, thread safety, high locking performance
  • It is recommended to use
public class LazySafeInner {
    private LazySafeInner(a){}private static class LazySafeInnerHolder{
        private static LazySafeInner lazySafeInner=new LazySafeInner();
    }
    public static LazySafeInner getInstance(a){
        returnLazySafeInnerHolder.lazySafeInner; }}/ / test
class LazySafeInnerTest {
    public static void main(String[] args) {
        Thread t=newThread(()->{ LazySafeInner lazyUnSafe=LazySafeInner.getInstance(); System.out.println(lazyUnSafe); }); t.start(); LazySafeInner lazyUnSafe=LazySafeInner.getInstance(); System.out.println(lazyUnSafe); }}Copy the code

07, Enumeration (thread safety)

  • recommended
  • Thread-safe, free serialization, single instance
  • To prevent reflection
  • Do not apply to inheritance scenarios
public enum LazySafeEnum { INSTANCE; public void hello(){ System.out.println("hello "); }} / / test class LazySafeEnumTest {public static void main (String [] args) {LazySafeEnum. INSTANCE. Hello (); }}Copy the code