單例模式分為兩種:餓漢式和懶漢式(飽漢式)。
餓漢式:類加載的時候已經建立好了對象,随使随用。
建立步驟
1. 構造方法私有化,從外界不能構造此類的對象
2. 靜态私有變量 并初始化,類加載的時候已經被初始化
3. 提供一個靜态的公共的方法供外界通路
懶漢式(飽漢式):什麼時候用,再建立對象.需要注意線程安全問題,有延遲加載的特性。
建立步驟
1.構造方法私有化,從外界不能構造此類的對象
2.靜态私有變量,沒有被顯示初始化,隻是預設的null值
3.線程安全地獲得靜态私有對象變量的值
開發中常用餓漢式,代碼簡潔,沒有線程安全問題
JDK中的單例模式:Runtime類的源碼如下圖所示
顯而易見Runtime類是使用了餓漢式的單例模式
餓漢式:适用于單線程、多線程
package siglepattern;
/**
* 餓漢式 沒有線程安全問題
* @author feige
*/
public class StudentHungerPattern {
//構造方法私有化
private StudentHungerPattern(){
}
//靜态私有變量 并初始化
private static StudentHungerPattern student=new StudentHungerPattern();
//靜态的公共的方法供外界通路,來獲得對象
public static StudentHungerPattern getStudent(){
return student;
}
}
适用于單線程的懶漢式
package siglepattern;
//單線程下的延遲加載(懶漢式)
public class UnSafeLazyInitialization {
private static Instance instance=null;
public static Instance getInstance(){
if(instance==null){
instance=new Instance();
}
return instance;
}
//構造方法私有化
private UnSafeLazyInitialization(){}}
适用于多線程的懶漢式(效率不高)
package siglepattern;
/**
* 懶漢式(飽漢式)
* @author feige
*/
public class StudentFill {
private StudentFill(){}//構造方法私有化,
private static StudentFill student=null;
public synchronized static StudentFill getStuddent(){//注意線程安全
if(student==null){
student=new StudentFill();
}
return student;
}
}
由于對getStudent()方法作了同步處理,synchronized将導緻性能開銷
多線程下懶漢式的同步處理優化---》安全的雙重檢查鎖定
1.volatile(适用于執行個體字段、靜态字段的初始化)
package siglepattern;
public class SafeDoubleChekedLocking {
private volatile static Instance instance=null;
public static Instance getInstance(){
if(instance==null){
synchronized(SafeDoubleChekedLocking.class){
if(instance==null){
instance=new Instance();
}
}
}
return instance;
}
private SafeDoubleChekedLocking(){}
}
2.基于類初始化(适用于靜态字段的初始化)
package siglepattern;
public class InstanceFactory {
private static class InstanceHolder{
public static Instance instance=new Instance();
}
public static Instance getInstance(){
return InstanceHolder.instance;
}
}
我們一般使用volatile對執行個體字段進行初始化,靜态字段的初始化用基于類初始化