📜  演示单例类双重检查锁定的Java程序

📅  最后修改于: 2022-05-13 01:54:18.366000             🧑  作者: Mango

演示单例类双重检查锁定的Java程序

初级开发人员面临的主要挑战之一是如何将 Singleton 类保持为 Singleton,即如何防止 Singleton 类的多个实例。 Singleton 的双重检查锁定是一种确保在应用程序生命周期中仅创建 Singleton 类实例的一种方法。在双重检查锁定中,代码在锁定和不锁定的情况下两次检查 Singleton 类的现有实例,以确保只创建一个单例实例。

单例类的双重检查锁定的需要:

Java
private static Singleton instance;
  
public static Singleton getInstance1()
{
    if (instance == null) {
        instance = new Singleton();
    }
    return instance;
}


Java
public static Singleton getInstance2()
{   // Single Checked
    if (instance == null) { 
        
        synchronized (Singleton.class)
        { 
            // Double checked
            if (instance == null) { 
                instance = new Singleton();
            }
        }
    }
    return instance;
}


Java
// Java Program to write double checked locking 
// of Singleton class
  
class Singleton {
    private volatile static Singleton instance;
  
    private Singleton() {}
  
    // 1st version: creates multiple instances if two thread
    // access this method simultaneously
    public static Singleton getInstance1()
    {
        if (instance == null) {
            instance = new Singleton();
        }
  
        return instance;
    }
  
    // 2nd version : this is thread-safe and only
    // creates one instance of Singleton on concurrent
    // environment but it is unnecessarily expensive due to
    // cost of synchronization at every call.
    public static synchronized Singleton getInstance2()
    {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
  
    // 3rd version : An implementation of double checked
    // locking of Singleton. Intention is to reduce cost
    // of synchronization and improve performance, by only
    // locking critical section of code, the code which
    // creates instance of Singleton class.
    public static Singleton getInstance3()
    {
        if (instance == null) {
            synchronized (Singleton.class)
            {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}


  • 如果由多个线程并行调用(称为多线程),上述代码将创建 Singleton 类的多个实例。
  • 当前问题的主要解决方案是使getInstance() 方法同步。
  • 虽然它是线程安全的,解决了多实例的问题,但效率不高。每次调用这个方法都需要承担同步的代价,而同步只需要在第一类,当创建 Singleton 实例时。

这给我们带来了双重检查锁定模式,其中只有代码的关键部分被锁定。

为什么称为双重检查锁定?

  • 它被称为双重检查锁定,因为有两个检查,例如 == null,一个没有锁定,另一个有锁定(在同步块内)。

双重检查锁定在Java中的样子:

Java

public static Singleton getInstance2()
{   // Single Checked
    if (instance == null) { 
        
        synchronized (Singleton.class)
        { 
            // Double checked
            if (instance == null) { 
                instance = new Singleton();
            }
        }
    }
    return instance;
}

在 Singleton 类上实现双重检查锁定:

Java

// Java Program to write double checked locking 
// of Singleton class
  
class Singleton {
    private volatile static Singleton instance;
  
    private Singleton() {}
  
    // 1st version: creates multiple instances if two thread
    // access this method simultaneously
    public static Singleton getInstance1()
    {
        if (instance == null) {
            instance = new Singleton();
        }
  
        return instance;
    }
  
    // 2nd version : this is thread-safe and only
    // creates one instance of Singleton on concurrent
    // environment but it is unnecessarily expensive due to
    // cost of synchronization at every call.
    public static synchronized Singleton getInstance2()
    {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
  
    // 3rd version : An implementation of double checked
    // locking of Singleton. Intention is to reduce cost
    // of synchronization and improve performance, by only
    // locking critical section of code, the code which
    // creates instance of Singleton class.
    public static Singleton getInstance3()
    {
        if (instance == null) {
            synchronized (Singleton.class)
            {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}