Java面試必備:手寫單例模式

面試官:請手寫下幾種常見的單例模式
我:好的(面帶微笑),內心暗喜(送分題)。
沒成想提筆便寫出瞭如此豪放的代碼,不堪回首,請原諒個人不羈!
java

在這裏插入圖片描述
此篇整理了幾種常見的單例模式代碼示例,再有面試官讓手撕單例模式,便能心中有碼,下筆有神。

爲何要有單例模式

實際編程應用場景中,有一些對象其實咱們只須要一個,好比線程池對象、緩存、系統全局配置對象等。這樣能夠就保證一個在全局使用的類不被頻繁地建立與銷燬,節省系統資源。面試

實現單例模式的幾個要點

  1. 首先要確保全局只有一個類的實例。
    要保證這一點,至少類的構造器要私有化。
  2. 單例的類只能本身建立本身的實例。
    由於,構造器私有了,可是還要有一個實例,只能本身建立咯!
  3. 單例類必須可以提供本身的惟一實例給其餘類
    就是要有一個公共的方法能返回該單例類的惟一實例。

單例模式的6種實現

一、餓漢式—靜態常量方式(線程安全)

public class Singleton {  
    private static Singleton instance = new Singleton();  
    private Singleton (){}  
    public static Singleton getInstance() {  
    return instance;  
    }  
}
複製代碼

類加載時就初始化實例,避免了多線程同步問題。自然線程安全。編程

二、餓漢式—靜態代碼塊方式(線程安全)

其實就是在上面 靜態常量餓漢式 實現上稍微變更了一下,將類的實例化放在了靜態代碼塊中而已。其餘沒區別。緩存

public class Singleton {
    private static Singleton instance;
    static {
        instance = new Singleton();
    }
    private Singleton() {}
    public static Singleton getInstance() {
        return instance;
    }
}
複製代碼

三、懶漢式(線程不安全)

public class Singleton {
    private static Singleton singleton;
    private Singleton() {}
    public static Singleton getInstance() {
        if (singleton == null) {
            singleton = new Singleton();
        }
        return singleton;
    }
}
複製代碼

這是最基本的實現方式,第一次調用才初始化,實現了懶加載的特性。多線程場景下禁止使用,由於可能會產生多個對象,再也不是單例。安全

四、懶漢式(線程安全,方法上加同步鎖)

public class Singleton {
    private static Singleton singleton;
    private Singleton() {}
    public static synchronized Singleton getInstance() {
        if (singleton == null) {
            singleton = new Singleton();
        }
        return singleton;
    }
}
複製代碼

和上面 懶漢式(線程不安全)實現上惟一不一樣是:獲取實例的getInstance()方法上加了同步鎖。保證了多線程場景下的單例。可是效率會有所折損,不過還好。多線程

五、雙重校驗鎖(線程安全,效率高)

public class Singleton {
	private volatile static Singleton singleton;
	private Singleton() {}
	public static Singleton getSingleton() {
		if (singleton == null) {
			synchronized (Singleton.class) {
				if (singleton == null) {
						singleton = new Singleton();
				}
			}
		}
		return singleton;
	}
}
複製代碼

此種實現中不用每次須要得到鎖,減小了獲取鎖和等待的事件。
注意volatile關鍵字的使用,保證了各線程對singleton靜態實例域修改的可見性。spa

六、靜態內部類實現單例(線程安全、效率高)

public class Singleton {  
    private static class SingletonHolder {  
    private static final Singleton INSTANCE = new Singleton();  
    }  
    private Singleton (){}  
    public static final Singleton getInstance() {  
    return SingletonHolder.INSTANCE;  
    }  
}
複製代碼

這種方式下 Singleton 類被裝載了,instance 不必定被初始化。由於 SingletonHolder 類沒有被主動使用,只有經過顯式調用 getInstance 方法時,纔會顯式裝載 SingletonHolder 類,從而實例化 instance。
注意內部類SingletonHolder要用static修飾且其中的靜態變量INSTANCE必須是final的。線程

此篇完。單例模式掌握至此,足以應付「手寫單例」的面試場景。code

相關文章
相關標籤/搜索