確保乙個類只有乙個例項,並提供該例項的全域性訪問點。
使用乙個私有建構函式、乙個私有靜態變數以及乙個公有靜態函式來實現。
私有建構函式保證了不能通過建構函式來建立物件例項,只能通過公有靜態函式返回唯一的私有靜態變數。
執行緒不安全問題主要是由於 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...