面試中常問的單例設計模式

一。單例設計模式(SINGLETON)概念

在整個應用生命週期內只存在一個例項,叫做單例,是廣泛使用的設計模式。優點是,避免多次建立例項,減少記憶體開銷。

二。面試中常問的問題

來手寫個單例設計模式:

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

請問這種方式有什麼壞處?

答:這個是懶漢式,存線上程安全問題,餓漢式我就不寫了。

那怎麼修復呢?

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

執行緒是安全了,請問有什麼缺點,有什麼更好的方式嗎?

答:確實代價太大了,我來再想想怎麼最佳化,你應該若有所思的樣子去思考。

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

面試官點點頭,還能最佳化嗎?

答:咱思考下,再最佳化下。

public class Singleton {    private volatile static Singleton instance;    private Singleton() {   }    public static Singleton getInstance() {        if (instance == null) {            synchronized (Singleton。class) {                if (instance == null) {                    instance = new Singleton();               }           }       }        return instance;   }}

為什麼這麼設計呢?

答:在instance = new Singleton()這一行,jvm會做如下操作:

給例項分配記憶體;

透過建構函式,成員變數初始化;

將instance指向分配的記憶體空間。但是他們順序有可能被打亂,也就是指令重排。在JDK5之後,使用volatile關鍵字,可以防止指令重排,保證了instance對所有的執行緒可見性。似乎一切在咱的掌握之中,面試官有可能還會問,還有其他的方式來保證執行緒安全嗎?前提是不使用synchronized關鍵字。

public

class

Singleton

{

private

Singleton

() {

}

public

static

Singleton

getInstance

() {

return

SingletonInner

instance

}

private

static

class

SingletonInner

{

static

final

Singleton

instance

=

new

Singleton

();

}

}

答:透過靜態記憶體類的方式,在初次載入類時,類的靜態屬性進行初始化, 並且JVM虛擬會保證併發訪問, 不會出現併發問題。由於靜態變數只初始化一次, 絕對可以保證單例。還有別的方式嗎?答:透過列舉。每個列舉常量,代表一個常量例項。且列舉例項不能被克隆,所以不能透過反射產生例項。而且列舉的建立,JVM會保證執行緒安全的,不存線上程安全問題。