一、雙重校驗鎖private
在Java中,使用雙重校驗鎖實現單例可以確保線程安全,並且實現懶加載。雙重校驗鎖是一種既有鎖又有條件判斷的機制。下面是一個示例代碼:
public class Singleton {
private volatile static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
在這個示例代碼中,instance是volatile變量,保證了其在多線程環境下的可見性,例如一個線程A將instance初始化為非空對象時,其他線程B可以馬上看到instance的更新而不出現臟讀。volatile這個關鍵字還可以保證instance賦值時的原子性。使用synchronized關鍵字保證了在instance對象創建完成之前,其他線程不能訪問該對象。
二、雙重校驗鎖實現對象單例
使用雙重校驗鎖實現對象單例,確保了在多線程環境下只有一個實例對象被創建,從而節省了系統資源。代碼實現如下:
public class Singleton {
private volatile static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
當一個線程進入getInstance()方法時,首先會判斷instance是否為空,如果為空則進入synchronized塊。進入synchronized塊後,再次判斷instance是否為空,如果為空,則創建Singleton對象,否則直接返回instance。這種方式可以避免多個線程同時調用getInstance()方法創建多個實例對象。
三、雙重校驗鎖能判空嗎
在實現雙重校驗鎖的過程中,必須注意對instance對象的空判斷。下面是一段錯誤示例代碼:
public class Singleton {
private volatile static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
return instance;
}
}
上面的代碼只在synchronized塊裡面對instance進行了判空,而在多線程環境下存在問題。當一個線程進入synchronized塊時,如果instance為空,線程會進入if語句並創建對象,其他線程在此時進入synchronized塊,在第一個線程還沒創建對象時就已經通過了instance的空判斷,會直接返回instance,此時instance是沒有被初始化的。這種錯誤引起了線程安全的問題。正確實現方式如前面的示例代碼所示。
四、雙重校驗鎖實現單例模式
單例模式是一種常用的設計模式,通過確保一個類只有一個實例,保證了全局唯一性和相應的資源共享。有多種方法可以實現單例模式,雙重校驗鎖就是其中之一。以下是使用雙重校驗鎖實現單例模式的示例代碼:
public class Singleton {
private volatile static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
在這個示例中,使用了volatile關鍵字修飾instance變量,因為Java的指令重排會導致多線程環境下單例不成功的問題。具體實現可以查看Java的內存模型(JMM)。synchronized保證了在創建Singleton對象時,只有一個線程會進入,其他線程會在外部等待。
五、單例模式雙重校驗鎖
雙重校驗鎖實現單例模式是一種非常常用的方式,但是在Java5及以後版本中,使用靜態類的方式來實現單例模式也是一個比較流行的方式。下面是使用雙重校驗鎖實現單例模式例子:
public class Singleton {
private static class SingletonHolder {
private static Singleton instance = new Singleton();
}
private Singleton() {}
public static Singleton getInstance() {
return SingletonHolder.instance;
}
}
上面的代碼通過一個私有靜態內部類來實現單例模式。SingletonHolder類中定義了一個靜態實例變量instance,只有在調用getInstance()方法時,該變量才被首次初始化,實現了懶加載的效果。由於靜態屬性SingletonHolder.instance只有在getInstance()方法被調用時才會被初始化,因此可以保證單例對象在初始加載時不會被初始化。這種實現方式是線程安全的。
六、單例模式雙重校驗鎖作用
單例模式雙重校驗鎖的作用可以歸納為以下幾點:
1、保證全局唯一性和相應的資源共享;
2、確保在多線程環境下只有一個實例對象被創建;
3、實現懶加載,避免程序初始化時的性能問題;
4、提高代碼可讀性和維護性。
七、雙重檢驗鎖單例
雙重檢驗鎖單例是一種常見的線程安全的單例模式實現方法。該實現基於java的volatile關鍵字實現線程間的內存可見性以及synchronized關鍵字實現互斥性訪問。下面是雙重檢驗鎖單例實現代碼:
public class Singleton {
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
在雙重檢驗鎖單例實現代碼中,instance變量需要加上volatile關鍵字修飾以保證線程間的內存可見性,instance變量的改變會立即刷新到主存當中,其他線程能夠立即看到instance最新的值。同時,getInstance()方法的實現也加上了synchronized關鍵字,以確保線程安全性,這樣只有一個線程能夠訪問getInstance()方法。在方法內部,實際上進行了兩次null檢查。第一次檢查時不加鎖,是為了避免多次執行加鎖操作造成性能問題。第二次檢查加上鎖,主要是為了防止多線程同時做到此處,導致instance初始化多次的問題。
以上是雙重校驗鎖的詳解。雙重校驗鎖是一種常用的代碼模式,能夠保證線程安全,並且實現懶加載。在實戰中需要掌握其正確實現方式,並且合理應用,以避免可能出現的線程安全問題。
原創文章,作者:NSXV,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/132114.html
微信掃一掃
支付寶掃一掃