單例(Singleton)
簡答的說就是整個jvm 中只有一個對象
單例分爲懶漢模式和餓漢模式
餓漢: 就是聲明對象的收直接new
public class Singleton {
private static Singleton singleton = new Singleton ();
private Singleton () {}
public static Singleton getInstance () {
return singleton;
}
}
懶漢: 在使用的時候創建對象
public class Singleton {
private static Singleton singleton;
private Singleton () {}
public static Singleton getInstance () {
if (singleton == null) {
singleton = new Singleton ();
}
return singleton;
}
}
以上的方式僅僅針對單線程,在併發情況下, 還是會存在多個singleton 對象.
synchronzied 直接加載方法上(不推薦,鎖太重),可以保證併發情況下的只有一個對象.
優化一下: (懶漢模式)
public class Singleton {
private static Singleton singleton;
private Singleton () {}
public static Singleton getInstance () {
if (singleton == null) {
synchonized (Singleton.class) {
singleton = new Singleton ();
}
}
return singleton;
}
}
但 這個還不是併發安全的方式
比如
thread 1 到 synchronized 處, thread 2 也到這裏,但是thread 2 繼續執行, 調用了構造器最後返回, thread 1 繼續執行, 又會執行一次構造器,然後返回,這就導致不是隻有一個對象.
再次優化 就出現 DCL(Double Check Lock) 單例, 在獲取鎖之後,再次檢驗對象是否爲 null
public class Singleton {
private static volatile Singleton singleton;
private Singleton () {}
public static Singleton getInstance () {
if (singleton == null) {
synchonized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton ();
}
}
}
return singleton;
}
}
這裏面使用了volatile, 因爲在對象初始化過程中,沒有 volatile ,會發生指令重排序的情況,導致使用半初始化的對象,有了volatile,會禁止指令重排序,所有的指令都是按照順序執行.