一、什麼是單例模式?
單例模式是一種對象創建型模式,使用單例模式,可以保證爲一個類只生成唯一的實例對象。也就是說,在整個程序空間中,該類只存在一個實例對象。其實,GoF對單例模式的定義是:保證一個類、只有一個實例存在,同時提供能對該實例加以訪問的全局訪問方法。
二、爲什麼要使用單例模式呢?
在應用系統開發中,我們常常有以下需求:
(1)、在多個線程之間,比如servlet環境,共享同一個資源或者操作同一個對象
(2)、在整個程序空間使用全局變量,共享資源
(3)、大規模系統中,爲了性能的考慮,需要節省對象的創建時間等等。
因爲SingIeton模式可以保證爲一個類只生成唯一的實例對象,所以這些情況,SingIeton模式就派上用場了。
三、單例模式的實現
(1)、餓漢式
(2)、懶漢式
(3)、雙重檢查
四、代碼實現:
(1)、餓漢模式:
創建Person類
package com.renxin.singleton;
public class Person {
public static final Person person = new Person();
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//構造函數私有化
private Person() {
}
//提供一個全局的靜態方法
public static Person getPerson() {
return person;
}
}
創建測試類MainClass
package com.renxin.singleton;
public class MainClass {
public static void main(String[] args) {
Person per = Person.getPerson();
Person per2 = Person.getPerson();
per.setName("zhangsan");
per2.setName("lisi");
System.out.println(per.getName());
System.out.println(per.getName());
}
}
控制檯打印結果爲:
lisi
lisi
(2)、懶漢式
創建Persion2類:
package com.renxin.singleton;
public class Person2 {
private String name;
private static Person2 person;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//構造函數私有化
private Person2() {
}
//提供一個全局的靜態方法
public static Person2 getPerson() {
if(person == null) {
person = new Person2();
}
return person;
}
}
創建測試類MainClass:
package com.renxin.singleton;
public class MainClass {
public static void main(String[] args) {
Person2 per = Person2.getPerson();
Person2 per2 = Person2.getPerson();
per.setName("zhangsan");
per2.setName("lisi");
System.out.println(per.getName());
System.out.println(per.getName());
}
}
控制檯打印結果爲:
lisi
lisi
五、懶漢式和餓漢式比較:
餓漢式是線程安全的,在類創建的同時就已經創建好一個靜態的對象供系統使用,以後不在改變。
懶漢式如果在創建實例對象時不加上synchronized則會導致對對象的訪問不是線程安全的。
推薦使用餓漢式:
從實現方式來講他們最大的區別就是懶漢式是延時加載,他是在需要的時候才創建對象,而餓漢式在虛擬機啓動的時候就會創建,餓漢式無需關注多線程問題、寫法簡單明瞭、能用則用。但是它是加載類時創建實例、所以如果是一個工廠模式、緩存了很多實例、那麼就得考慮效率問題,因爲這個類一加載則把所有實例不管用不用一塊創建。
懶漢式的優點是延時加載、缺點是應該用同步(想改進的話現在還是不可能,比如double-check)、其實也可以不用同步、看你的需求了,多創建一兩個無引用的廢對象其實也沒什麼大不了。
(3)、雙重檢查:
package com.renxin.singleton;
public class Person3 {
private String name;
private static Person3 person;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//構造函數私有化
private Person3() {
}
//提供一個全局的靜態方法
public static Person3 getPerson() {
if(person == null) {
synchronized (Person3.class) {
if(person == null) {
person = new Person3();
}
}
}
return person;
}
}
雙重檢查說白了就是對懶漢式的改進!