單例模式
定義
單例模式是一種對象創建型模式。使用單例模式,可以保證一個類只生成唯一的實例對象。也就是說,在整個程序空間中,該類只存在一個實例對象。
意義
提供對同一種資源的共享,節省創建對象的資源,提高效率。
爲了只能創建一個類的實例,可以將類的構造函數私有化,並提供公共的接口,對類實例對象進行訪問。
單列模式有分爲懶漢式和餓漢式。
1、懶漢式
在類初始化時,便創建對象
代碼如下:
public class Person {
private 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;
}
}
2、惡漢式
只有在需要類實例時,才進行創建
代碼如下:
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;
}
}
多線程中的處理
在單線程中,上面兩種方式是沒有問題的,但是在多線程中,可以看到懶漢式是沒有問題的,而惡漢式是多線程不安全的。
那麼該如何改進惡漢式在多線程中的應用呢,最簡單的情況,便是同步,代碼如下:
處理一
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 synchronized Person3 getPerson() {
if(person == null) {
person = new Person3();
}
return person;
}
}
可以看到,我們得到了想要的結果,但是仔細觀察,發現處理一中的方法,會造成資源的浪費。例如:當線程1訪問到getPerson()函數時,那麼其他的線程就會一直等待。特別是當實例已經創建成功,但是,每次進行if(person == null) 的判斷,也會進行同步,造成效率極低。
爲了改進處理一中的方法,可以考慮只對創建實例的方法進行同步,如下:
處理二
public class Person4 {
private String name;
private static Person4 person;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//構造函數私有化
private Person4() {
}
//提供一個全局的靜態方法
public static Person4 getPerson() {
if(person == null) {
synchronized (Person4.class) {
person = new Person4();
}
}
return person;
}
}
仔細觀察,處理二中的方法是多線程不安全的。例如:線程1訪問到synchronized (Person4.class) 時,線程2也剛好訪問到此處。那麼最終的結果便是,線程1創建了一個實例,線程2也創建了一個實例。
那麼,可以進步改進,如下:
處理三
public class Person5 {
private String name;
private static Person5 person;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//構造函數私有化
private Person5() {
}
//提供一個全局的靜態方法
public static Person5 getPerson() {
if(person == null) {
synchronized (Person5.class) {
if(person == null) {
person = new Person5();
}
}
}
return person;
}
}