java設計模式---(1)單例模式
阿新 • • 發佈:2018-12-14
單例模式
定義: 確保一個類只有一個例項, 而且自行例項化並向整個系統提供這個例項
保證只有一個例項,只能是不讓外面訪問的類的構造方法,所以就構造方法寫成私有的,向整個系統提供一個例項那麼就只能定義一個static的例項返回回去了,所以程式碼可以這樣寫:
public class Singelton { private static Singelton singelton = new Singelton(); private Singelton(){ // 構造方法私有化,就不能new一個Singelton物件了 } public static Singelton getSingelton() { // 通過getSingelton()來獲取已經準備好了的物件 return singelton; } }
驗證結果:
public static void main(String[] args) {
Singelton s1 = Singelton.getSingelton();
Singelton s2 = Singelton.getSingelton();
System.out.println(s1.equals(s2)); // true
}
結果說明2次呼叫返回的是同一個物件,其實這個沒什麼好驗證的,static 修飾的singelton物件在記憶體裡面必然是獨一份。
上面這個寫法就是通常所說的飽漢模式,所謂飽漢模式就是物件事先已經new好了,就像是吃飽了的。對應的就有個餓漢模式了,餓漢模式
於是把上面的飽漢模式改一下,成了下面這樣:
public class SingeltonHungry { private static SingeltonHungry hungry = null; private SingeltonHungry() { // 構造方法私有化,就不能new一個Singelton物件了 } public static SingeltonHungry getSingelton() { // getSingelton()來獲取物件,如果沒有就建立,有就直接返回 if (hungry == null) { hungry = new SingeltonHungry(); } return hungry; } }
在單執行緒下就不驗證了,跟上面一樣,返回的都是一個物件。但是在多執行緒的情況下就不一樣了,因為有個hungry == null
判斷,然後才new一個新物件。所以在hungry
物件最開始是null的時候如果2個執行緒同時執行上面的判空,然後都是true,然後就都去new了自己的物件了,這就不是單例了。
先寫個執行緒類:
public class TestThread implements Runnable {
@Override
public void run() {
SingeltonHungry singelton = SingeltonHungry.getSingelton();
System.out.println("SingeltonHungry的hashCode:"+singelton.hashCode());
}
}
然後來進行測試:
public static void main(String[] args) {
Thread t1 = new Thread(new TestThread());
Thread t2 = new Thread(new TestThread());
t1.start();
t2.start();
}
輸出結果是:
SingeltonHungry的hashCode:1734172372
SingeltonHungry的hashCode:1232133915
說明2個執行緒各自建立了一個例項。所以這樣的話就不是單例了。所以要改一下,給getSingelton()
方法加個同步鎖:
public class SingeltonHungry {
private static SingeltonHungry hungry = null;
private SingeltonHungry() { // 構造方法私有化,就不能new一個Singelton物件了
System.out.println("call constructor"); // 看呼叫了幾次構造方法
}
public static synchronized SingeltonHungry getSingelton() { // getSingelton()來獲取物件,如果沒有就建立,有就直接返回
if (hungry == null) {
hungry = new SingeltonHungry();
}
return hungry;
}
}
再次使用上面的測試方法來測試一下2個執行緒來建立例項的情況,輸出結果是:
call constructor
SingeltonHungry的hashCode:1481297610
SingeltonHungry的hashCode:1481297610
只輸出一次“call constructor” 並且兩個執行緒得到的物件是hashCode是一樣的,這足以說明2個執行緒建立最終得到的物件是同一個。
總結一下,單例模式3個點:
1.私有化構造方法,讓別人不能自主例項化物件
2.自己提供一個方法來建立一個靜態物件。
3.單例模式有2個型別:飽漢模式、餓漢模式(要注意多執行緒問題)