單例設計模式
//餓漢式
public class Singleton01 {
//1.私有的靜態的變量
privatestatic Singleton01 instance=new Singleton01();
//2.私有的構造器
privateSingleton01(){}
//3.共有的get()方法
publicstatic Singleton01 getInstance(){
returninstance;
}
}
//懶漢式
public class Singleton02 {
//1.私有的靜態的變量
privatestatic Singleton02 instance;
//2.私有的構造器
privateSingleton02(){
if(instance!=null){
thrownew RuntimeException();//防止反射和反序列化漏洞
}
}
//3.公有get方法
publicstatic synchronized Singleton02 getInstance(){
//要防止線程同步
if(null==instance){
returnnew Singleton02();//延時加載
}
returninstance;
}
}
//靜態內部類,兼備了高效調用和延遲加載的優勢
public class Singleton03 {
//外部類沒有static屬性,則不會像餓漢式那樣立即加載對象
privatestatic class SingletonClassInstance{
privatestatic final Singleton03 instance=new Singleton03();
}
//只有真正調用getInstance(),纔會加載靜態內部類。加載類時是線程安全的。instance是static final類型
//保證了內存中只有這樣一個實例存在,而且只能被賦值一次,從而保證了線程安全性
publicstatic Singleton03 getInstance(){
returnSingletonClassInstance.instance;
}
privateSingleton03(){}
}
1. 餓漢式是天然的線程安全的,但是沒有延遲加載的優勢。餓漢式之所以是天然的線程安全,是因爲:
一個字節碼文件被加載到內存會經歷以下過程:
1、鏈接(1、驗證2、準備3、解析)
2、初始化
3、使用
4、卸載
初始化是執行類構造器<clinit>()方法的過程。類構造器<clinit>()方法是由編譯器自動收集類中的所有類變量的賦值動作和靜態語句塊(static)中的語句合併產生的。在這個過程中instance已經被實例化了。並且虛擬機JVM會保證一個類的<clinit>()方法在多線程的環境中被正確加鎖和同步。因此他是天然線程安全的。
2. 懶漢式具有延遲加載的優勢,但是一般的懶漢式線程都不安全,而且有反射和反序列化的的漏洞,如上所寫便可防止反射反序列化的漏洞,而且線程安全,但是這樣一來調用效率變得很低。
3. 靜態內部類具有線程安全、延遲加載的優勢目前也比較常用到