懶漢式
加方法鎖
public class Singleton {
private static Singleton singleton = null;
private Singleton() {
}
public static synchronized Singleton getInstance() {
if (Objects.isNull(singleton)) {
singleton = new Singleton();
}
return singleton;
}
}
- 直接在 getInstance() 方法加鎖,但是加鎖的范圍太大,性能低下
雙重檢查鎖定
public class Singleton {
private static volatile Singleton singleton = null;
private Singleton() {
}
public static Singleton getInstance() {
// 1
if (Objects.isNull(singleton)) {
synchronized(Singleton.class) {
if (Objects.isNull(singleton)) {
// 2
singleton = new Singleton();
}
}
}
return singleton;
}
}
對(duì)象需要加volatile 關(guān)鍵字,主要是防止指令重排序。
singleton = new Singleton();方法在執(zhí)行的時(shí)候有三個(gè)指令:memory = allocate(); // 1:分配對(duì)象的內(nèi)存空間 ctorInstance(memory); // 2:初始化對(duì)象 instance = memory; // 3:設(shè)置instance指向剛分配的內(nèi)存地址當(dāng)線程A獲取到鎖,執(zhí)行初始化的時(shí)候發(fā)生了指令重排,1->3->2。當(dāng)2還沒有被執(zhí)行時(shí),線程B執(zhí)行到代碼標(biāo)記1的位置,這時(shí)判斷到對(duì)象不為空,直接返回該對(duì)象,但是這個(gè)時(shí)候該對(duì)象可能還并沒有完成初始化,導(dǎo)致線程B在執(zhí)行過程中拋錯(cuò)。
靜態(tài)內(nèi)部類
public class Singleton {
private static class LazyHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton() {
}
public static Singleton getInstance() {
return LazyHolder.INSTANCE;
}
}
既實(shí)現(xiàn)了線程安全,又避免了同步帶來的性能影響。JVM在類的初始化階段(即在Class被加載后,且被線程使用之前),會(huì)執(zhí)行類的初始化。在 執(zhí)行類的初始化期間,JVM會(huì)去獲取一個(gè)鎖。這個(gè)鎖可以同步多個(gè)線程對(duì)同一個(gè)類的初始化。使用這種方式,我們是允許
new Singleton();過程發(fā)生指令重排的。
使用枚舉的形式
public class EnumSingleton {
private EnumSingleton() {
}
public static EnumSingleton getInstance() {
return Singleton.INSTANCE.getInstance();
}
private enum Singleton {
INSTANCE(new EnumSingleton());
private EnumSingleton singleton;
//JVM會(huì)保證此方法絕對(duì)只調(diào)用一次
Singleton(EnumSingleton singleton) {
this.singleton = singleton;
}
public EnumSingleton getInstance() {
return singleton;
}
}
}
JVM會(huì)保證枚舉類構(gòu)造方法絕對(duì)只調(diào)用一次,所以保證了對(duì)象實(shí)例的唯一性
餓漢式
public class Singleton {
private static final Singleton singleton = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return singleton;
}
}