建立型模式之單例模式

2021-10-11 18:09:47 字數 3796 閱讀 8318

確保乙個類只有乙個例項,並提供該例項的全域性訪問點。

使用乙個私有建構函式、乙個私有靜態變數以及乙個公有靜態函式來實現。

私有建構函式保證了不能通過建構函式來建立物件例項,只能通過公有靜態函式返回唯一的私有靜態變數。

執行緒不安全問題主要是由於 uniqueinstance 被例項化多次,採取直接例項化 uniqueinstance 的方式就不會產生執行緒不安全問題。

但是直接例項化的方式也丟失了延遲例項化帶來的節約資源的好處。

public

class

singleton

public

static singleton getuniqueinstance()

}

私有靜態變數 uniqueinstance 被延遲例項化,這樣做的好處是,如果沒有用到該類,就不會例項化 uniqueinstance,從而節約資源。

這個實現在多執行緒環境下是不安全的,如果多個執行緒能夠同時進入if (uniqueinstance == null),並且此時 uniqueinstance 為 null,就會有多個執行緒執行uniqueinstance = new singleton();語句,這將導致例項化多次 uniqueinstance。

public

class

singleton

public

static singleton getuniqueinstance()

return uniqueinstance;

}}

直接對 getuniqueinstance() 方法加鎖,那麼在乙個時間點只能有乙個執行緒能夠進入該方法,從而避免了例項化多次 uniqueinstance。

但是當乙個執行緒進入該方法之後,即使 uniqueinstance 已經被例項化了,其它試圖進入該方法的執行緒也必須等待。這會讓執行緒阻塞時間過長,因此該方法有效能問題,不推薦使用。

public

class

singleton

public

static

synchronized singleton getuniqueinstance()

return uniqueinstance;

}}

uniqueinstance 只需要被例項化一次,之後就可以直接使用了。只有當 uniqueinstance 沒有被例項化時,才需要對例項化部分的**進行加鎖。

雙重校驗鎖先判斷 uniqueinstance 是否已經被例項化,如果沒有被例項化,那麼才對例項化語句進行加鎖。

public

class

singleton

public

static singleton getuniqueinstance()

}}return uniqueinstance;

}}

考慮下面的實現,也就是只使用了乙個 if 語句。在 uniqueinstance == null 的情況下,如果兩個執行緒都執行了 if 語句,那麼兩個執行緒都會進入 if 語句塊內。雖然在 if 語句塊內有加鎖操作,但是兩個執行緒都會執行uniqueinstance = new singleton();這條語句,只是先後的問題,那麼就會進行兩次例項化。因此必須使用雙重校驗鎖,也就是需要使用兩個 if 語句:

第乙個 if 語句用來避免 uniqueinstance 已經被例項化之後的加鎖操作,

第二個 if 語句進行了加鎖,所以只能有乙個執行緒進入,就不會出現 uniqueinstance == null 時兩個執行緒同時進行例項化操作。

if

(uniqueinstance == null)

}

uniqueinstance 採用 volatile 關鍵字修飾也是很有必要的,uniqueinstance = new singleton();這段**其實是分三步執行:

為 uniqueinstance 分配記憶體空間

初始化 uniqueinstance

將 uniqueinstance 指向分配的記憶體位址

但是由於 jvm 具有指令重排的特性,執行順序有可能變成 1>3>2。指令重排在單執行緒環境下不會出現問題,但是在多執行緒環境下會導致乙個執行緒獲得還沒有初始化的例項。例如,執行緒 t1 執行了 1 和 3,此時 t2 呼叫 getuniqueinstance() 後發現 uniqueinstance 不為空,因此返回 uniqueinstance,但此時 uniqueinstance 還未被初始化。

使用 volatile 可以禁止 jvm 的指令重排,保證在多執行緒環境下也能正常執行。

當 singleton 類被載入時,靜態內部類 singletonholder 沒有被載入進記憶體。只有當呼叫getuniqueinstance()方法從而觸發singletonholder.instance時 singletonholder 才會被載入,此時初始化 instance 例項,並且 jvm 能確保 instance 只被例項化一次。

這種方式不僅具有延遲初始化的好處,而且由 jvm 提供了對執行緒安全的支援。

public

class

singleton

private

static

class

singletonholder

public

static singleton getuniqueinstance()

}

該實現可以防止反射攻擊。在其它實現中,通過 setaccessible() 方法可以將私有建構函式的訪問級別設定為 public,然後呼叫建構函式從而例項化物件,如果要防止這種攻擊,需要在建構函式中新增防止多次例項化的**。該實現是由 jvm 保證只會例項化一次,因此不會出現上述的反射攻擊。

該實現在多次序列化和序列化之後,不會得到多個例項。而其它實現需要使用 transient 修飾所有字段,並且實現序列化和反序列化的方法。

public

class

singleton

//定義乙個靜態列舉類

static

enum singletonenum

public singleton getinstnce()

}//對外暴露乙個獲取user物件的靜態方法

public

static singleton getinstance()

}

1、防止反射破環(雖然構造方法已私有化,但通過反射機制使用newinstance()方法構造方法也是可以被呼叫):

2、防止轉殖破環

3、防止序列化破環

public

class

singleton

implements

serializable

,cloneable}}

else

}public

static singleton getinstance()

}}return singleton;

}@override

protected singleton clone()

throws clonenotsupportedexception

private object readresolve()

}

建立型模式之單例模式

功能 保證乙個類僅有乙個例項,並提供乙個訪問它的全域性訪問點。優點 缺點 模式應用 乙個具有自動編號主鍵的表可以有多個使用者同時使用,但資料庫中只能有乙個地方分配下乙個主鍵編號,否則會出現主鍵重複,因此該主鍵編號生成器必須具備唯一性,可以通過單例模式來實現。舉例 在os中,列印池 print spo...

建立型模式之單例模式

1.對於系統中的某些類來說,只有乙個例項很重要,例如,乙個系統中可以存在多個列印任務,但是只能有乙個正在工作的任務 乙個系統只能有乙個視窗管理器或檔案系統 乙個系統只能有乙個計時工具或id 序號 生成器。2.單例模式 singleton pattern 單例模式確保某乙個類只有乙個例項,而且自行例項...

建立型模式 單例模式

餓漢式 package com.hfview.designmode.signle 1.餓漢式 就是在初始化成員變數的時候就獲取例項物件 2.public class signlemode private signlemode 懶漢式 package com.hfview.designmode.sig...