單例模式
由於是進階,基礎的餓漢式與懶漢式單例模式就不在這裏說明了,雙重檢查的寫法也沒什麼可講的,算是高級一點放上代碼吧,雙重檢查:
public class DoubleCheckSingleton {
//私有化構造方法
private DoubleCheckSingleton(){};
//自己作爲屬性: 添加volatile 修飾,使其對所有線程可見
private volatile static DoubleCheckSingleton instansce;
public static DoubleCheckSingleton getInstance(){
if (instansce==null){
synchronized (DoubleCheckSingleton.class){
if (instansce==null){
instansce=new DoubleCheckSingleton();
}
}
}
return instansce;
}
}
提一下,只有懶漢式纔會有線程安全問題,餓漢式是沒有的.
重點
下面這種方式是研磨設計模式中提到的一種非常巧妙的單例模式實現方法,先上代碼:
public class Singleton {
/**
* 類級的內部類,也就是靜態的成員式內部類,該內部類的實例與外部類的實例沒有綁定關係,
* 而且只有被調用到時纔會裝載,從而實現延遲加載.
*/
private static class SingletonHolder{
//靜態初始化器,由JVM保證
private static Singleton instance = new Singleton();
}
//私有化構造方法
private Singleton(){};
public static Singleton getInstance(){
return SingletonHolder.instance;
}
}
上述方式的思路:
1.解決的問題:同時實現線程安全和延遲加載,並且不通過synchronized關鍵在加鎖(影響訪問效率);
2.解決思路:JVM有幾種情況會隱式的進行同步控制:
- 由靜態初始化器(在靜態字段上或static{}代碼塊的初始化器)初始化數據時
- 訪問final字段時
- 在創建線程之前創建對象時
- 線程可以看到它將要處理的對象時
我們使用的就是第一種情況,當getInstance方法第一次被調用的時候,它纔會第一次 調用SingletonHolder.instance,導致SingletonHolder類得到初始化,而這個類在裝載並被初始化的時候會初始化它的靜態域,從而創建Singleton的實例,由於是靜態的域,所以只會在JVM加載類的時候初始化一次,並由虛擬機保證其安全性.這種寫法的優勢在於getInstance方法沒有被同步,Singleton實例也只是在內部類被加載(getInstance方法第一次被調用的時候),纔會裝載一次,因此延遲初始化並沒有增加任何訪問成本.
最後,大招:
public enum Single {
singleTon;
public void oprate(String s){
System.out.println(s);
}
}