更新時(shí)間:2021-09-30 來源:黑馬程序員 瀏覽量:
單例模式有很多實(shí)現(xiàn)方法,餓漢、懶漢、靜態(tài)內(nèi)部類、枚舉類,試分析每種實(shí)現(xiàn)下獲取單例對(duì)象(即調(diào)用getInstance)時(shí)的線程安全,并思考注釋中的問題。
餓漢式:類加載就會(huì)導(dǎo)致該單實(shí)例對(duì)象被創(chuàng)建
懶漢式:類加載不會(huì)導(dǎo)致該單實(shí)例對(duì)象被創(chuàng)建,而是首次使用該對(duì)象時(shí)才會(huì)創(chuàng)建
1. 餓漢單例
// 問題1:為什么加 final
// 問題2:如果實(shí)現(xiàn)了序列化接口, 還要做什么來防止反序列化破壞單例
public final class Singleton implements Serializable {
// 問題3:為什么設(shè)置為私有? 是否能防止反射創(chuàng)建新的實(shí)例?
private Singleton() {}
// 問題4:這樣初始化是否能保證單例對(duì)象創(chuàng)建時(shí)的線程安全?
private static final Singleton INSTANCE = new Singleton();
// 問題5:為什么提供靜態(tài)方法而不是直接將 INSTANCE 設(shè)置為 public, 說出你知道的理由
public static Singleton getInstance() {
return INSTANCE;
}
public Object readResolve() {
return INSTANCE;
}
}
2.枚舉單例
// 問題1:枚舉單例是如何限制實(shí)例個(gè)數(shù)的
// 問題2:枚舉單例在創(chuàng)建時(shí)是否有并發(fā)問題
// 問題3:枚舉單例能否被反射破壞單例
// 問題4:枚舉單例能否被反序列化破壞單例
// 問題5:枚舉單例屬于懶漢式還是餓漢式
// 問題6:枚舉單例如果希望加入一些單例創(chuàng)建時(shí)的初始化邏輯該如何做
enum Singleton {
INSTANCE;
}
3. 懶漢單例
public final class Singleton {
private Singleton() { }
private static Singleton INSTANCE = null;
// 分析這里的線程安全, 并說明有什么缺點(diǎn)
public static synchronized Singleton getInstance() {
if( INSTANCE != null ){
return INSTANCE;
}
INSTANCE = new Singleton();
return INSTANCE;
}
}
4. DCL 懶漢單例
public final class Singleton {
private Singleton() { }
// 問題1:解釋為什么要加 volatile ?
private static volatile Singleton INSTANCE = null;
// 問題2:對(duì)比實(shí)現(xiàn)3, 說出這樣做的意義
public static Singleton getInstance() {
if (INSTANCE != null) {
return INSTANCE;
}
synchronized (Singleton.class) {
// 問題3:為什么還要在這里加為空判斷, 之前不是判斷過了嗎
if (INSTANCE != null) { // t2
return INSTANCE;
}
INSTANCE = new Singleton();
return INSTANCE;
}
}
}
5. 靜態(tài)內(nèi)部類懶漢單例
public final class Singleton {
private Singleton() { }
// 問題1:屬于懶漢式還是餓漢式
private static class LazyHolder {
static final Singleton INSTANCE = new Singleton();
}
// 問題2:在創(chuàng)建時(shí)是否有并發(fā)問題
public static Singleton getInstance() {
return LazyHolder.INSTANCE;
}
}
猜你喜歡: