天天看點

一文看懂Java Singleton單例模式

定義: 在整個運作過程中,一個類隻有一個執行個體對象

為什麼要用?

有些對象建立消耗資源,如果頻繁建立和銷毀那将會造成性能浪費,是以我們要用單例模式。

常用的一種方法

public class Singleton {
  private volatile static Singleton singleton;
  private Singleton () {

  }
  public static  Singleton getSingleton() {
    if (null  == singleton) {
      synchronized (Singleton.class) {
        if (null == singleton) {
          singleton = new Singleton();
        }
      }
    }
    return singleton;
  }
}
class main {
  public static void main(String[] args) {
    System.out.println(Singleton.getSingleton());

  }
}      

主要從1、是否線程安全 2 是否懶加載 3 能否反射破壞(人為)

===========================

下面是其他各類方法

一:隻适用單線程環境(不推薦)

/**
 * @author kegekeqi
 * @version 1.0
 * @date 2021-12-7 7:50
 */
public class Javasingleton {
  private Javasingleton() {

  }
  private static Javasingleton instance = null;
  public static Javasingleton getInstance() {
    if (null == instance) {
      instance = new Javasingleton();
    }
    return instance;
  }
}      

二、加同步鎖前後兩次判斷執行個體是否存在,也稱為雙重檢測鎖

好處:隻有當instance為null時,需要擷取同步鎖,建立一次執行個體。當執行個體被建立,則無需試圖加鎖。

缺點:用雙重if判斷,複雜,容易出錯。

/**
 * @author kegekeqi
 * @version 1.0
 * @date 2021-12-7 7:50
 */
public class Javasingleton {
  private Javasingleton() {

  }
  private static Javasingleton instance = null;
  public static Javasingleton getInstance() {
    if (null == instance) {
      synchronized (Javasingleton.class) {
        if (null == instance) {
          instance = new Javasingleton();
        }
      }
    }
    return instance;
  }
}      

可能到這裡了,大家會提起經常說到的懶漢式、餓漢式和枚舉,不要急一一列舉,哪種最好用,好好思考一下。

三、餓漢模式

public class HungryManMode {
    private static HungryManMode hungryManMode = new HungryManMode();
    private HungryManMode(){};
    public static HungryManMode getHungryManMode(){
        return hungryManMode;
    }
}      

餓漢模式在類加載的時候就對執行個體進行建立,避免了多線程重複建立執行個體的問題,但是類加載就建立一定程度造成了記憶體的浪費。

四、懶漢模式

public class LazyManMode {
    private static LazyManMode lazyManMode = null;
    private LazyManMode(){};
    public static synchronized LazyManMode getLazyManMode(){
        if(lazyManMode == null){
            lazyManMode = new LazyManMode();
        }
        return lazyManMode;
    }
}      

懶漢模式中在單例需要的時候才進行建立,為了解決存在的并發問題,使用synchronized關鍵字 進行限制,也就造成了一定的性能浪費

五、枚舉

// Singledto.class
public class Singledto implements Serializable {}

// EnumSingleton.class
public enum EnumSingleton {
    ;
    private Singledto singledto;

    private EnumSingleton(){
        singledto = new Singledto();
    }

    public Singledto getSingledto(){
        return singledto;
    }
}      

枚舉中的執行個體被保證隻會被執行個體化一次,是以需要的執行個體也會保證執行個體化一次,枚舉強烈推薦

六、靜态内部類(建議使用)

按需建立執行個體

由于私有的屬性,他人無法使用SingleHolder,不調用SingletonHolder.getInstance()就不會建立執行個體。

public class JavaSingleton {
  private JavaSingleton() {

  }
  private static class SingletonHolder {
    private final static JavaSingleton instance = new JavaSingleton();
  }
  public static JavaSingleton getInstance() {
    return SingletonHolder.instance;
  }
}      

除此之外,還有利用C#的靜态構造函數,確定隻建立一個執行個體。還有利用私有嵌套類型的特性做到真正需要的時候才會建立執行個體,提高空間使用效率,減少資源的浪費。

補充:比如懶漢式可以人為用反射去破壞,防止這種事情發生可以用枚舉類。