關於單例模式的N種實現方式

2022-07-07 09:54:11 字數 2559 閱讀 1403

在開發中經常用到單例模式,單例模式也算是設計模式中最容易理解,也是最容易手寫**的模式,所以也常作為面試題來考。所以想總結一下單例模式的理論知識,方便同學們面試使用。

單例模式實現的方式只有兩種型別,一種是餓漢式(類載入時就初始化)、一種是懶漢式(類載入時不初始化)。餓漢式沒什麼可講究的因為它既簡單也執行緒安全,如果條件允許一般我們都會直接用餓漢式;唯獨比較麻煩的是懶漢式,考慮到執行緒安全,使用懶漢式的單例模式,就有多種實現方式了。

一、餓漢式

如上所述,餓漢式很簡單,實現方式如下:

public

class

singleton

public

static

singleton getinstance()

}

這種單例模式,很簡單而且還安全,可以說近乎完美。它唯一的缺陷就是,這種實現方式就無法適用於單例還需要一定的配置或者傳參的場景。

二、懶漢式

懶漢式的單例模式,由於要考慮到執行緒安全的情況,有多種實現方式。

0、如下的實現方式是一種不安全的實現方式

public

class

singleton

public

static

singleton getinstance()

return

instance;

}}

之所以把定義為編號0,就是除非你非常確定沒有多執行緒的場景,因為當有多個執行緒並行呼叫 getinstance() 的時候,就會建立多個例項。所以絕大部分場景下,這種實現方式都是不應該使用。

1、低效能的懶漢式

public

static

synchronized

singleton getinstance()

if (instance == null

)

return

instance;

}

這種實現方式,解決了多執行緒例項問題,但是由於直接在方法上使用synchronized關鍵字,即類鎖同步,使得只能使用每次呼叫都要進行同步操作,效能比較低。

2、雙重檢驗鎖的懶漢式

public

class

singleton

public

static

singleton getsingleton() }}

return

instance;

}}

我們看到最多的情況就是沒有加volatile的情形,其實你不加這個關鍵字,面試你的人應該也不會糾結於這個,因為99.99%的情況都是好的(要知道那些提供後台服務的,一般只會保證99%可靠性……)。之所以加是因為jvm存在指令重排的優化,導致

new singleton() 不是乙個原子操作行為,new singleton() 這句話執行的過程大概分為以下abc步驟:

a, 給 instance 分配記憶體;

b, 呼叫 singleton 的建構函式來初始化成員變數;

c, 將instance物件指向分配的記憶體空間(執行完這步 instance 就為非 null 了);

jvm 的即時編譯器中存在指令重排序的優化,執行順序可能是 abc 也可能是 acb。如果是acb,在執行到c,被執行緒x搶占了,這時 instance 已經是非 null 了(但卻沒有初始化),所以執行緒x會直接返回 instance,使用乙個沒有初始化的例項產生錯誤是必然的。那為什麼要加volatile呢?一般我們只用到volatile的可見性功能,即對乙個volatile變數的讀,總是能看到(任意執行緒)對這個volatile變數最後的寫入,而且經常用於解決同步問題。其實volatile還有乙個重要的功能——禁止指令重排優化,也就是volatile標記的變數不會被編譯器優化。如上所示,加上volatile以後,讀操作一定會發生在abc或者acb之後,並且這個順序是固定。

3、靜態內部類實現懶漢式

public

class

singleton

private

singleton (){}

public

static

final

singleton getinstance()

}

由於internalsingleton 是私有的,除了 getinstance() 之外沒有辦法訪問它,因此它是懶漢式的;同時讀取例項的時候不會進行同步,沒有效能缺陷。

4、通過列舉實現懶漢式

通過列舉寫單例超級簡單,什麼都不用想,這也是它最大的優點。下面這段**就是宣告列舉例項的通常做法。

public

enum

singleton

}

我們可以通過singleton.instance來訪問例項,這比呼叫getinstance()方法簡單多了。建立列舉預設就是執行緒安全的,所以不需要擔心double checked locking,而且還能防止反序列化導致重新建立新的物件。可能由於平時我們使用列舉都是為了表示類別,大家都很少使用這種方式去寫單例模式。

Android的單例模式的N種實現方式

說起androidd的23種設計模式,恐怕大多數人不能說全,但是說起單例模式,大多數人不管是初級開發還是資深開發工程師都應該知道並且使用過。單例模式應該是最簡單也是比較常用的設計模式了。但是你真的了解單例模式嗎?最近看了 android原始碼設計模式 這本書,才發現我原來理解的單例模式太冰山一角了。...

關於單例模式

單例模式 只能產生乙個例項物件 思路 不能外部new,只能內部new 構造方法要私有,構造方法私有後只能類自己呼叫 需要將物件 通過類自己的來構造例項 的引用變數設定成static修飾的這樣就屬於類本身,只有乙份,即乙個例項物件 構造的物件需要提供給外部,由於無法new物件來呼叫這個方法,因此需要乙...

7種方式實現單例模式

單例模式,即是整個類有且只有乙個類例項,通過這個唯一的例項為全域性提供服務。單例類的構造方法為私有的,通過乙個暴露給外界的獲取例項方法來呼叫私有構造方法,保證例項的唯一性。因為餓漢式單例在類載入時就初始化了唯一的例項 且只會初始化一次,所以,該例項是唯一的,即 執行緒安全的 因此,如果我們想要為例項...