關於java中的double check lock
##實現一個正確的單例模式
在熟悉的單例模式中你或許會遇到下面的方式來實現一個單例:
// version 1
class Singleton {
private static Singleton _INSTANCE
static Singleton getInstance() {
if (_INSTANCE == null) {
_INSTANCE = new Singleton()
}
return _INSTANCE;
}
}
但是這個在多執行緒環境下會有問題:
Problem 1: 這個會建立多個Singleton物件.
那麼我可以加上下面的同步就可以了:
// version 2
class Singleton {
private static Singleton _INSTANCE
static synchronized Singleton getInstance() {
if (_INSTANCE == null) {
_INSTANCE = new Singleton()
}
return _INSTANCE;
}
}
這是一個完全正確的版本, 除了效能比較差.
那麼我們可以直接不使用lazy init, 就可以不需要同步了:
// version 3
class Singleton {
private static final Singleton _INSTANCE = new Singleton()
static Singleton getInstance() {
return _INSTANCE;
}
}
這裡final不是必須的.
static為我們提供了保證(正確的被建立, 建立的物件是完整的) 可以參考:JSR 133 (Java Memory Model) FAQ
恩 這很不錯, 除了 也許我根本不需要它, 但是有可能我們需要用到的時候才建立.
所以, 便引出我們今天的雙重檢查版本:
// version 4
class Singleton {
private static Singleton _INSTANCE
static Singleton getInstance() {
if (_INSTANCE == null) {
synchronized (Singleton.class) {
if (_INSTANCE) {
_INSTANCE = new Singleton()
}
}
}
return _INSTANCE;
}
}
這個程式碼是無法工作的. 因為這個可能讓其他執行緒看到沒有完全構件好的物件:
// 原始程式碼
_INSTANCE = new Singleton()
// 實際上的步驟:
1.allocateMemory -> object
2.Singleton._INSTANCE = object
3.init object attributes
實際上我們對2,3 的步驟是無法保證,
也就是如果2先執行 (指令重排), 那麼其他執行緒可能看到構建了一半的物件.
所以常見的可以在多執行緒下正確工作的單例模式:
- static init
- object holder
- synchronized 在class上同步
- 把instance標記為volatile. 因為volatile會禁止上面的重排(>=JDK1.4).
//object holder
private static class LazySomethingHolder {
public static Something something = new Something();
}
public static Something getInstance() {
return LazySomethingHolder.something;
}
Reference:
1.https://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
2.https://www.ibm.com/developerworks/java/library/j-dcl/index.html
相關文章
- 關於MYSQL中FLOAT和DOUBLE型別的儲存MySql型別
- [Oracle Script] check lock infoOracle
- Java併發程式設計實戰--雙重檢查加鎖( double check lock)與延遲初始化佔位Java程式設計
- 關於Java中的equals方法Java
- C語言中關於float、double、long double精度及數值範圍理解C語言
- 關於SAP中的Check and update optimizer statistics任務(Oracle CBO在SAP中的應用)Oracle
- Double-check idiom for lazy initialization of instance fields
- 關於DFS lock handle等待事件事件
- 關於 Java 中的 RMI-IIOPJava
- Java 中關於protected的介紹Java
- 關於Java中的反射機制Java反射
- 關於Java中的@Deprecated註解Java
- 關於Java中類的成員Java
- 關於 ReentrantLock 中鎖 lock() 和解鎖 unlock() 的底層原理淺析ReentrantLock
- 關於java中的i++和++iJava
- 關於java中的類載入器Java
- 關於j_security_check的問題 高手請指教
- 有關於JAVA中的CLASSPATH的作用 (轉)Java
- 如何在Java中將double轉換為int?Java
- java中lock介面是什麼Java
- 關於Java中類似於Portal starter的專案Java
- Java併發指南4:Java中的鎖 Lock和synchronizedJavasynchronized
- 關於JAVA中順序IO的基本操作Java
- 關於Java中列舉Enum的深入剖析Java
- java中關於Map的九大問題Java
- 關於java中的記憶體洩漏Java記憶體
- 關於java中Excel的匯入匯出JavaExcel
- 關於Java中的類和物件筆記Java物件筆記
- java關鍵字詳解(abstract.double.int.switch) (轉)Java
- 工作學習筆記(十)Java 中 “<” 運算子不能應用於BigDecimal和double筆記JavaDecimal
- java double、float型別的比較Java型別
- Java 中關於 null 物件的容錯處理JavaNull物件
- Java 疑惑集之Double篇Java
- mysql關於FLUSH TABLES和FLUSH TABLES WITH READ LOCK的理解MySql
- 關於enq: TX - row lock contention行鎖的總結ENQ
- JAVA_LockJava
- 盤點關於Java在生活中的應用!Java
- Java中關於二分查詢的問題Java