工作深度總結——雙重鎖定實現單例

ZeroWM發表於2018-02-06

程式碼段

   private static volatile OSSClient ossClient;

    private static OSSClient getOssClient() {
        if (ossClient == null) {
            synchronized (OSSClient.class) {
                if (ossClient == null) {
                    ossClient = new OSSClient(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);
                    Runtime.getRuntime().addShutdownHook(new Thread(() -> ossClient.shutdown()));
                }
            }
        }
        return ossClient;
    }

關鍵程式碼解析

原子性

 synchronized 確保當前只有一個執行緒例項化oss客戶端

可見性

 volatitle 全域性共享變數,在Java5之後,遵循happens-before原則,一旦被改變,立刻寫入記憶體,寫優先於讀。

有序性

synchronized 保證了執行緒的有序性

鉤子

 已經初始化,但是並不啟動的執行緒,jvm退出之前,進行ossClient的關閉。


程式碼邏輯解析

 首先判斷ossClient是否為空,如果不為空,就直接返回;如果為空,就先鎖定當前的類,允許一個執行緒進入。

然後再次判斷ossClient是否被初始化。如果沒有被初始化,就new 一個ossClient;如果被初始化,就直接返回例項化物件。

 如果沒有通過volatitle 修飾,可能會報錯,因為JVM主要進行三個操作:1.給 ossClient 分配記憶體 2.呼叫 Singleton 的建構函式來初始化成員變數

3. 將ossClient物件指向分配的記憶體空間(執行完這步ossClient就為非 null 了),2和3的操作順序未知,如果先進行3,然後再進行2操作,ossClient不為空,

2還沒有完成,返回就會報錯。

 Java5之後,通過volatitle修飾,保證寫優先於讀,所以如果判斷ossClient 不為空,那麼初始化一定完成。


總結

編寫優秀的程式碼,就像欣賞一首美妙的歌曲,美好的事物,誰不喜歡呢~



相關文章