轉(zhuǎn)自:http://blog.csdn.net/willamlan/article/details/48596237
設(shè)計(jì)模式之-------單例模式
在現(xiàn)有的23種設(shè)計(jì)模式中,可以說單例模式是所有設(shè)計(jì)模式中最簡(jiǎn)單的一種。
單例模式就是說系統(tǒng)中對(duì)于某類的只能有一個(gè)對(duì)象,不可能再出來第二個(gè)。
通過單例模式,自行實(shí)例化并向這個(gè)系統(tǒng)提供這個(gè)單一實(shí)例的訪問方法。
單例模式也是23中設(shè)計(jì)模式中在面試時(shí)少數(shù)幾個(gè)會(huì)要求寫代碼的模式之一。
主要考察的是多線程下單例模式的線程安全性問題。
單例模式實(shí)例一(不使用同步鎖)
public class Singleton {
private static Singleton sin=new Singleton(); ///直接初始化一個(gè)實(shí)例對(duì)象
private Singleton(){ ///private類型的構(gòu)造函數(shù),保證其他類對(duì)象不能直接new一個(gè)該對(duì)象的實(shí)例
}
public static Singleton getSin(){ ///該類唯一的一個(gè)public方法
return sin;
}
}
上述代碼中的一個(gè)缺點(diǎn)是該類加載的時(shí)候就會(huì)直接new 一個(gè)靜態(tài)對(duì)象出來,當(dāng)系統(tǒng)中這樣的類較多時(shí),會(huì)使得啟動(dòng)速度變慢 ?,F(xiàn)在流行的設(shè)計(jì)都是講“延遲加載”,我們可以在第一次使用的時(shí)候才初始化第一個(gè)該類對(duì)象。所以上述這種只適合在小系統(tǒng)。
單例模式實(shí)例二(使用同步方法)
public class Singleton {
private static Singleton instance;
private Singleton (){
}
public static synchronized Singleton getInstance(){ //對(duì)獲取實(shí)例的方法進(jìn)行同步
if (instance == null)
instance = new Singleton();
return instance;
}
}
上述代碼中的一次鎖住了一個(gè)方法, 這個(gè)粒度有點(diǎn)大 ,改進(jìn)就是只鎖住其中的new語句就OK。就是所謂的“雙重鎖”機(jī)制。
單例模式實(shí)例三(使用雙重同步鎖)
public class Singleton {
private static Singleton instance;
private Singleton (){
}
public static Singleton getInstance(){ //對(duì)獲取實(shí)例的方法進(jìn)行同步
if (instance == null){
synchronized(Singleton.class){
if (instance == null)
instance = new Singleton();
}
}
return instance;
}
}
附注:根據(jù)此單一實(shí)例產(chǎn)生的時(shí)機(jī)不同(當(dāng)然,都是指第一次,也是唯一一次產(chǎn)生此單一實(shí)例時(shí)),可以將其分為懶漢式、餓漢式和登記式。
一、懶漢式:
其特點(diǎn)是延遲加載,即當(dāng)需要用到此單一實(shí)例的時(shí)候,才去初始化此單一實(shí)例。如上面的單例模式實(shí)例二。
二、餓漢式:
餓漢式的特點(diǎn)是應(yīng)用中尚未需要用到此單一實(shí)例的時(shí)候即先實(shí)例化。如上面的單例模式實(shí)例一。
三、登記式單例模式:
登記式單例模式,一般是通過一個(gè)專門的類對(duì)各單例模式的此單一實(shí)例進(jìn)行管理和維護(hù)。通過Map方式可以方便的實(shí)現(xiàn)此中目的。常見的代碼如下:
import java.util.HashMap;
import java.util.Map;
public class SingleTonManager {
private static Map singleTonMap = new HashMap();
public static void main(String[] args) {
// 獲取A類的單例
A a = (A) getInstance(A.class.getName());
// 獲取B類的單例
B b = (B) getInstance(B.class.getName());
}
// 根據(jù)類型獲取單例
public static Object getInstance(String className) {
// 判斷singleTonMap中是否有此單例,有則取得后返回,無則添加單例后返回
if (!singleTonMap.containsKey(className)) {
try {
singleTonMap.put(className, Class.forName(className).newInstance());
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return singleTonMap.get(className);
}
}
class A {
}
class B {
}
四、改進(jìn)型懶漢式(直接滿足線程安全)——通過靜態(tài)內(nèi)部類實(shí)現(xiàn)
在如上的懶漢單例模式中,對(duì)于多線程環(huán)境中。可以通過常見的如synchronized等方式實(shí)現(xiàn)線程安全,同時(shí),可以通過Java靜態(tài)內(nèi)部類的方式實(shí)現(xiàn)進(jìn)一步改進(jìn)。
常見代碼如下:
public class SingleTon {
// 利用靜態(tài)內(nèi)部類特性實(shí)現(xiàn)外部類的單例
private static class SingleTonBuilder {
private static SingleTon singleTon = new SingleTon();
}
// 私有化構(gòu)造函數(shù)
private SingleTon() {
}
public static SingleTon getInstance() {
return SingleTonBuilder.singleTon;
}
public static void main(String[] args) {
SingleTon instance = getInstance();
}
}
其主要原理為:Java中靜態(tài)內(nèi)部類可以訪問其外部類的成員屬性和方法,同時(shí),靜態(tài)內(nèi)部類只有當(dāng)被調(diào)用的時(shí)候才開始首次被加載,利用此特性,可以實(shí)現(xiàn)懶漢式,在靜態(tài)內(nèi)部類中靜態(tài)初始化外部類的單一實(shí)例即可。