ü 核心:保證一個類僅有一個實例,並提供一個訪問它的全局訪問點;
ü 用途:想保證某個特定類的對象實例絕對只有1個的情況;
ü 結構圖:
ü 方法:可以把類的屬性定義爲static字段,再以Singleton類的對象實例進行初始化,而這個初始化的操作僅僅在加載Singleton類時進行一次,Singleton類的構造函數是private的(所有類都有構造方法,不編碼則系統默認生成空的構造方法,若有顯示定義的構造方法,默認的構造方法就會失效,因此寫成private,外部程序就不能用new來實例化該類了),主要是爲了禁止從非Singleton類調用構造函數new出新的實例,而向要取得Singleton類的惟一對象實例的方法就是getInstance。
ü 單例模式和實用類的區別:實用類通常也會採用私有化的構造方法來避免其有實例,但是實用類不保存狀態,僅提供一些靜態方法或者靜態屬性讓你使用,而單例類是有狀態的,實用類不能用於繼承多態,而單例雖然實例唯一,卻是可以有子類來繼承的,實用類只不過是一些方法屬性的集合,而單例卻是有這唯一的對象實例。
ü 還需要注意,在多線程的程序中,多個線程同時訪問Singleton類,調用getInstance方法,會有可能造成創建多個實例。這個時候可以利用JAVA裏的線程同步機制,爲getInstance方法添加synchronized關鍵字(但不能對單例的實例化對象instance添加鎖,因爲該對象可能尚未實例化),而避免每次加鎖影響性能,可以使用”雙重鎖定”(Double-Check Locking):
說明:仔細觀察,我們不難發現,上述程序中有兩個地方需要判斷instance是否爲空,這主要是因爲:當instance爲null並且同時有兩個線程調用GetInstance()方法時,它們都將可以通過第一重instance == null的判斷,然後由於lock機制,這兩個線程則只有一個可以進入,另一個在外排隊等候,必須要其中的一個進入並出來後,另一個才能進入,而不要誤以爲只能執行其中一個,因此沒有第二重的Instance是否爲空的判斷,則兩個線程都會同時創建出實例,沒有達到單例的目的。
實例一:
Ø 單例類 -- 文件Singleton.java
package com.yilong.designpattern.singleton;
public class Singleton {
private static Singleton singleton = new Singleton();
private int ticketId = 1000;
private Singleton() {
System.out.println("已產生對象實例");
}
public static Singleton getInstance() {
return singleton;
}
public int getNextTicketId() {
return ticketId ++;
}
}
Ø 測試類 – 文件Main.java
package com.yilong.designpattern.singleton;
public class Main {
public static void main(String[] args) {
System.out.println("Start");
Singleton singleton1 = Singleton.getInstance();
Singleton singleton2 = Singleton.getInstance();
System.out.println(singleton1 == singleton2);
System.out.println(singleton1);
System.out.println(singleton2);
System.out.println(singleton1.getNextTicketId());
System.out.println(singleton2.getNextTicketId());
System.out.println("End");
}
}
打印結果:
Start
已產生對象實例
true
com.yilong.designpattern.singleton.Singleton@c17164
com.yilong.designpattern.singleton.Singleton@c17164
1000
1001
End
實例二:通過判斷對象實例是否爲空的方法實例化,但是這種方法在多線程的結構下可能達不到預期的效果,所以最好在方法前添加關鍵字synchronized。
Ø 單例類 – 文件Singleton1.java
package com.yilong.designpattern.test;
public class Singleton1 {
private static Singleton1 testSingleton = null;
private Singleton1() {
System.out.println("初始化!");
}
public static synchronized Singleton1 getInstance() {
if(testSingleton == null) {//儘管加入了鎖,但這個判斷還是必須的
testSingleton = new Singleton1();
}
return testSingleton;
}
}
實例三:實例數目有限個的情況。
Ø 文件Singleton2.java
package com.yilong.designpattern.test;
public class Singleton2 {
public static final int SIZE = 3;
private int id;
private static Singleton2[] singletons =
{new Singleton2(0), new Singleton2(1), new Singleton2(2)};
private Singleton2(int id) {
System.out.println("初始化!");
this.id = id;
}
public static synchronized Singleton2 getInstance(int id) {
if(id>=0 && id<=3) {
return singletons[id];
} else {
return null;
}
}
}
Ø 測試類 – 文件Test2.java
package com.yilong.designpattern.test;
public class Test1 {
public static void main(String[] args) {
System.out.println("Start");
Singleton2 singleton1 = Singleton2.getInstance(0);
Singleton2 singleton2 = Singleton2.getInstance(1);
Singleton2 singleton3 = Singleton2.getInstance(2);
Singleton2 singleton4 = Singleton2.getInstance(0);
System.out.println(singleton1);
System.out.println(singleton2);
System.out.println(singleton3);
System.out.println(singleton1 == singleton4);
System.out.println("End");
}
}
打印結果:
Start
初始化!
初始化!
初始化!
com.yilong.designpattern.test.Singleton2@c17164
com.yilong.designpattern.test.Singleton2@1fb8ee3
com.yilong.designpattern.test.Singleton2@61de33
true