高效能的執行緒安全單例——Java基礎語法系列
阿新 • • 發佈:2018-11-26
大家都知道,一般實現單例有兩種寫法: 餓漢式 和 懶漢式, 餓漢式是執行緒安全的,在編譯期間已完成初始化,載入到了記憶體裡。 懶漢式一般寫法是非執行緒安全的, 那懶漢式的執行緒安全單例應該如何實現呢,以及如何寫出低耗能的執行緒安全單例呢 ?
單例實現關鍵點
- 建構函式私有,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();
}
}
}