歡迎轉載,請附出處:
http://blog.csdn.net/as02446418/article/details/47952947
單例模式(Singleton)
首先來明確一個問題,那就是在某些情況下,有些對象,我們只需要一個就可以了,
比如,一臺計算機上可以連好幾個打印機,但是這個計算機上的打印程序只能有一個,
這裏就可以通過單例模式來避免兩個打印作業同時輸出到打印機中,
即在整個的打印過程中我只有一個打印程序的實例。
簡單說來,單例模式(也叫單件模式)的作用就是保證在整個應用程序的生命週期中,
任何一個時刻,單例類的實例都只存在一個(當然也可以不存在)。
單例模式的結構圖
從上面的類圖中可以看出,在單例類中有一個構造函數 Singleton ,
但是這個構造函數卻是私有的(前面是“ - ”符號),
然後在裏面還公開了一個 GetInstance()方法,
通過上面的類圖不難看出單例模式的特點,從而也可以給出單例模式的定義
單例模式保證一個類僅有一個實例,同時這個類還必須提供一個訪問該類的全局訪問點。
下面來看代碼:
public class Singleton1 {
private static Singleton1 instance;
private Singleton1(){
System.out.println("我是線程不安全的餓漢singleton");
}
public static Singleton1 getSingleton1(){
if (instance==null) {
instance = new Singleton1();
}
return instance;
}
}
如上面代碼所示,這種寫法是最不推薦的,也是因爲它的線程不安全,我們來看一下測試代碼和運行結果:
線程不安全的singleton
public class SingletonTest {
public static void main(String[] args){
for (int i = 0; i < 100; i++) {
new Thread(new Runnable() {
@Override
public void run() {
Singleton1.getSingleton1();
}
}).start();
}
}
}
這裏new了三個singleton,在多線程環境下可能存在多個線程判斷instance==null,所以會分別new出自己的instance,這顯然違背了單例模式的初衷。
接下來我們換種寫法:
線程安全的餓漢singleton
public class Singleton2 {
private static Singleton2 instance = new Singleton2();
private Singleton2(){
System.out.println("我是線程安全的餓漢singleton");
}
public static Singleton2 getSingleton1(){
return instance;
}
}
下面是運行結果:
爲什麼說是餓漢的singleton,因爲如上面代碼所示,在用到示例instance之前就已經把它初始化好了,雖然這裏是線程安全的,但是也會影響性能,所以我們來看第三種singleton。
線程安全的懶漢singleton
public class Singleton {
private Singleton(){
System.out.println("我是線程安全的singleton");
}
private static class singletonHolder{
private final static Singleton instance = new Singleton();
}
public static Singleton getSingleton(){
return singletonHolder.instance;
}
}
下面是運行結果:
如上述代碼所示,這裏用到了singletonHolder這個內部類,這個內部類只會在singletonHolder.instance中用到,也就是用的時候纔會初始化,故稱爲懶漢singleton,這樣既解決了多線程下不安全的問題,同時也解決了提前初始化影響的性能問題,所以是最推薦的一種寫法。