高性能的線程安全單例 — Java基礎語法系列

大家都知道,一般實現單例有兩種寫法: 餓漢式 和 懶漢式, 餓漢式是線程安全的,在編譯期間已完成初始化,加載到了內存裏。 懶漢式一般寫法是非線程安全的, 那懶漢式的線程安全單例應該如何實現呢,以及如何寫出低耗能的線程安全單例呢 ?

單例實現關鍵點

  • 構造函數私有,private
  • 實例對象 靜態 且 私有
  • 公開獲取實例的靜態方法

下面我們直接上代碼了,按重要程度排序,提供三種方式:

一、高性能的線程安全單例 - 懶漢式

關鍵注意點:

  • volatile 關鍵字修飾實例對象, 禁止指令重排序
  • 加鎖實例初始化過程
  • 判斷實例對象爲空時,進行雙重校驗
package safe;

/**
 * @description 線程安全的單例——懶漢式加載
 * @author [email protected]
 * @date 2018/11/20
 */
public class LazySingleton {
    /**
     * volatile 修飾屬性,簡直指令重排序
     */
    private static volatile LazySingleton lazySingleton = null;

    private LazySingleton() {
        //模擬: 創建線程爲耗時操作
        try {
            Thread.sleep(1000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static LazySingleton getInstance()  {
    	// 雙重校驗
        if (null == lazySingleton) {
            synchronized(LazySingleton.class) {
                if (lazySingleton == null) {
                    lazySingleton = new LazySingleton();
                }
            }
        }
        return lazySingleton;
    }

    public static void main(String args[]) {
        for (int i = 0; i < 10; i ++) {
            new Thread(() -> {
                System.out.println(LazySingleton.getInstance());
            }).start();
        }
    }
}

二、線程安全單例 - 懶漢式

同樣是懶漢式,但是這次實現的方式不一樣,我們直接選擇在 獲取實例的方法上,加上同步鎖, 但是缺點就是有點消耗性能。

package safe;

/**
 * @description 線程安全的單例-懶漢-消耗性能
 * 將 Sychronized 關鍵字加載方法上,消耗性能
 * @author [email protected]
 * @date 2018/11/20
 */
public class LazySingleton_SyncMethod {
    private LazySingleton_SyncMethod() {}
    private static LazySingleton_SyncMethod instance = null;
    public static synchronized LazySingleton_SyncMethod getInstance() {
        if (instance == null) {
            instance = new LazySingleton_SyncMethod();
        }
        return  instance;
    }

    public static void main(String args[]) {
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                System.out.println(LazySingleton_SyncMethod.getInstance());
            }).start();
        }
    }
}

三、線程安全單例-餓漢式

編譯期間,直接完成了初始化。

package safe;

/**
 *
 * @description  餓漢單例
 * @author [email protected]
 * @date 2018/11/20
 */
public class HungerSingleton {
    private static HungerSingleton ourInstance = new HungerSingleton();

    public static HungerSingleton getInstance() {
        return ourInstance;
    }

    private HungerSingleton() {
    }

    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            new Thread(() -> {
                System.out.println(HungerSingleton.getInstance());
            }).start();
        }
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章