1. 程式人生 > >Java設計模式之單例模式

Java設計模式之單例模式

設計 return 線程安全 -s ron none 方法 有一個 ava

  一、前言:

  轉載需要註明出處: https://i.cnblogs.com/EditPosts.aspx?opt=1

  單例模式其實很早之前就已經接觸過了,但都是為了應付面試或者是為了裝X。每過一段時間後,又有些模糊不清了,也仿佛從來沒有項目中使用過,但最近終於有它的用武之地了。

  二、單例模式的特點:

    • 單例類只能有一個實例
    • 單例類自己給自己創建一個實例,註意是唯一的一個實例
    • 單例類必須給其他對象提供這唯一的實例

  三、單例模式分類:

    • 懶漢模式

      懶漢模式即懶加載,第一次被調用前不實例化。對於創建實例代價大,且不一定會使用時,使用懶加載模式可以減少開銷

    • 餓漢模式

      餓漢模式,在類加載的同時實例化對象

  四、實現單例模式的各種方法:

    • 線程不安全的懶漢模式
public  class LazySingleton {
     private LazySingleton() {

    }
    private  static LazySingleton single;
     public  static LazySingleton getSinton(){
         if (single == null ){
            single = new LazySingleton();
        }
        
return single; } }

    這種方法在單線程場景中,是安全的,但在多線程情況中,單例模式未必是單例模式,也就是存在線程安全問題。

    • 同步方法下的多線程
public class LazySingleton {
    private LazySingleton() {

    }
    private static LazySingleton single;
    public static synchronized LazySingleton getSinton(){
        if(single == null){
            single 
= new LazySingleton(); } System.out.println(Thread.currentThread().getName()+": "+single); return single; } }

    使用sychronized修飾獲取實例對象的方法,這種方法可以保證線程安全,但效率不高,每個線程都需要來獲取 對象鎖。

    • 同步代碼塊的懶漢模式
public class LazySingleton {
    private LazySingleton() {

    }

    private static LazySingleton single;

    public static LazySingleton getSinton() {
        if (single == null) {
            synchronized (LazySingleton.class) {
                single = new LazySingleton();
            }
        }
        System.out.println(Thread.currentThread().getName() + ": " + single);
        return single;
        
    }
}

    由同步方法想到同步代碼塊,但實際上,這種方法並不是線程安全。

    解釋:兩個線程A、B,A線程判斷single是空的 ,當獲取到鎖後;B線程開始判斷,發現single是空的;這時A線程又快人一步,創建了一個對象;線程B來了,獲取到鎖,也創建了一個對象。

    • 雙重檢查的懶漢  
public class LazySingleton {
    private LazySingleton() {

    }

    private static LazySingleton single;

    public static LazySingleton getSinton() {
        if (single == null) {
            synchronized (LazySingleton.class) {
                if(single== null){
                    single = new LazySingleton();
                }
            }
        }
        System.out.println(Thread.currentThread().getName() + ": " + single);
        return single;
        
    }
}

    針對同步代碼塊的懶漢,雙重檢查的懶漢可以說是最佳的,既保證了線程安全,又不需要每次都獲取鎖資源。(推薦雙重檢查懶漢)

    • 靜態常量餓漢
public class HungrySingleTon {
    
    private HungrySingleTon(){
    }
    
    private final static HungrySingleTon single = new HungrySingleTon();
    
    public static HungrySingleTon getInstance(){
        return single;
    }
}

    無線程安全問題,缺點是類裝在完成實例化,若一直未使用,會造成資源浪費。

    • 靜態代碼塊餓漢模式
public class HungrySingleTon {

    private HungrySingleTon() {

    }

    private static HungrySingleTon single;

    static {
        single = new HungrySingleTon();
    }

    public static HungrySingleTon getInstance() {
        return single;
    }
}

      線程安全,與常量餓漢模式一樣,若一直未被使用,會造成資源浪費。

    • 靜態內部類
public class HungrySingleTon {

    private HungrySingleTon() {

    }

    public  static HungrySingleTon getInstance() {
         return InnerClass.single;
    }

    private  static  class InnerClass {
         private  static  final HungrySingleTon single = new HungrySingleTon();
    }
}

    只有調用getInstance()時才會加載靜態內部類。無線程安全問題,也實現了懶加載。

  

  

  

  

Java設計模式之單例模式