雙重校驗鎖詳解

一、雙重校驗鎖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-tw/n/132114.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
NSXV的頭像NSXV
上一篇 2024-10-03 23:49
下一篇 2024-10-03 23:50

相關推薦

  • 神經網路代碼詳解

    神經網路作為一種人工智慧技術,被廣泛應用於語音識別、圖像識別、自然語言處理等領域。而神經網路的模型編寫,離不開代碼。本文將從多個方面詳細闡述神經網路模型編寫的代碼技術。 一、神經網…

    編程 2025-04-25
  • Linux sync詳解

    一、sync概述 sync是Linux中一個非常重要的命令,它可以將文件系統緩存中的內容,強制寫入磁碟中。在執行sync之前,所有的文件系統更新將不會立即寫入磁碟,而是先緩存在內存…

    編程 2025-04-25
  • 詳解eclipse設置

    一、安裝與基礎設置 1、下載eclipse並進行安裝。 2、打開eclipse,選擇對應的工作空間路徑。 File -> Switch Workspace -> [選擇…

    編程 2025-04-25
  • Java BigDecimal 精度詳解

    一、基礎概念 Java BigDecimal 是一個用於高精度計算的類。普通的 double 或 float 類型只能精確表示有限的數字,而對於需要高精度計算的場景,BigDeci…

    編程 2025-04-25
  • MPU6050工作原理詳解

    一、什麼是MPU6050 MPU6050是一種六軸慣性感測器,能夠同時測量加速度和角速度。它由三個感測器組成:一個三軸加速度計和一個三軸陀螺儀。這個組合提供了非常精細的姿態解算,其…

    編程 2025-04-25
  • nginx與apache應用開發詳解

    一、概述 nginx和apache都是常見的web伺服器。nginx是一個高性能的反向代理web伺服器,將負載均衡和緩存集成在了一起,可以動靜分離。apache是一個可擴展的web…

    編程 2025-04-25
  • Linux修改文件名命令詳解

    在Linux系統中,修改文件名是一個很常見的操作。Linux提供了多種方式來修改文件名,這篇文章將介紹Linux修改文件名的詳細操作。 一、mv命令 mv命令是Linux下的常用命…

    編程 2025-04-25
  • C語言貪吃蛇詳解

    一、數據結構和演算法 C語言貪吃蛇主要運用了以下數據結構和演算法: 1. 鏈表 typedef struct body { int x; int y; struct body *nex…

    編程 2025-04-25
  • Python安裝OS庫詳解

    一、OS簡介 OS庫是Python標準庫的一部分,它提供了跨平台的操作系統功能,使得Python可以進行文件操作、進程管理、環境變數讀取等系統級操作。 OS庫中包含了大量的文件和目…

    編程 2025-04-25
  • Python輸入輸出詳解

    一、文件讀寫 Python中文件的讀寫操作是必不可少的基本技能之一。讀寫文件分別使用open()函數中的’r’和’w’參數,讀取文件…

    編程 2025-04-25

發表回復

登錄後才能評論