国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

單例模式與雙重檢查鎖定(double-checked locking)

yearsj / 2522人閱讀

摘要:對于而言,它執行的是一個個指令。在指令中創建對象和賦值操作是分開進行的,也就是說語句是分兩步執行的。此時線程打算使用實例,卻發現它沒有被初始化,于是錯誤發生了。

1.餓漢式單例

public class Singleton        
{        
    private static Singleton instance = new Singleton();        
    private Singleton(){        
        …        
    }        
    public static Singleton getInstance(){        
             return instance;         
    }        
} 

這樣的代碼缺點是:第一次加載類的時候會連帶著創建Singleton實例,這樣的結果與我們所期望的不同,因為創建實例的時候可能并不是我們需要這個實例的時候。同時如果這個Singleton實例的創建非常消耗系統資源,而應用始終都沒有使用Singleton實例,那么創建Singleton消耗的系統資源就被白白浪費了。

為了避免這種情況,我們通常使用惰性加載的機制,也就是在使用的時候才去創建。以上代碼的惰性加載代碼如下:
2.懶漢式單例

public class Singleton{        
    private static Singleton instance = null;        
    private Singleton(){        
        …        
    }        
    public static Singleton getInstance(){        
        if (instance == null)        
            instance = new Singleton();         
                return instance;         
    }        
} 

線程安全問題

這是如果兩個線程A和B同時執行了該方法,然后以如下方式執行:

A進入if判斷,此時instance為null,因此進入if內

B進入if判斷,此時A還沒有創建instance,因此instance也為null,因此B也進入if內

A創建了一個instance并返回

B也創建了一個instance并返回

此時問題出現了,我們的單例被創建了兩次,而這并不是我們所期望的。

3 各種解決方案及其存在的問題
3.1 使用Class鎖機制
以上問題最直觀的解決辦法就是給getInstance方法加上一個synchronize前綴,這樣每次只允許一個現成調用getInstance方法:

public static synchronized Singleton getInstance(){        
    if (instance == null)        
    instance = new Singleton();         
    return instance;         
}  

這種解決辦法的確可以防止錯誤的出現,但是它卻很影響性能:每次調用getInstance方法的時候都必須獲得Singleton的鎖,而實際上,當單例實例被創建以后,其后的請求沒有必要再使用互斥機制了

3.2 double-checked locking
曾經有人為了解決以上問題,提出了double-checked locking的解決方案

public static Singleton getInstance(){        
    if (instance == null)        
        synchronized(instance){        
            if(instance == null)        
                instance = new Singleton();        
        }        
    return instance;         
} 

讓我們來看一下這個代碼是如何工作的:首先當一個線程發出請求后,會先檢查instance是否為null,如果不是則直接返回其內容,這樣避免了進入synchronized塊所需要花費的資源。其次,即使第2節提到的情況發生了,兩個線程同時進入了第一個if判斷,那么他們也必須按照順序執行synchronized塊中的代碼,第一個進入代碼塊的線程會創建一個新的Singleton實例,而后續的線程則因為無法通過if判斷,而不會創建多余的實例。

上述描述似乎已經解決了我們面臨的所有問題,但實際上,從JVM的角度講,這些代碼仍然可能發生錯誤。
對于JVM而言,它執行的是一個個Java指令。在Java指令中創建對象和賦值操作是分開進行的,也就是說instance = new Singleton();語句是分兩步執行的。但是JVM并不保證這兩個操作的先后順序,也就是說有可能JVM會為新的Singleton實例分配空間,然后直接賦值給instance成員,然后再去初始化這個Singleton實例。(即先賦值指向了內存地址,再初始化)這樣就使出錯成為了可能,我們仍然以A、B兩個線程為例:

A、B線程同時進入了第一個if判斷

A首先進入synchronized塊,由于instance為null,所以它執行instance = new Singleton();

由于JVM內部的優化機制,JVM先畫出了一些分配給Singleton實例的空白內存,并賦值給instance成員(注意此時JVM沒有開始初始化這個實例),然后A離開了synchronized塊。

B進入synchronized塊,由于instance此時不是null,因此它馬上離開了synchronized塊并將結果返回給調用該方法的程序。

此時B線程打算使用Singleton實例,卻發現它沒有被初始化,于是錯誤發生了。

4 通過內部類實現多線程環境中的單例模式
為了實現慢加載,并且不希望每次調用getInstance時都必須互斥執行,最好并且最方便的解決辦法如下:

public class Singleton{        
    private Singleton(){        
        …        
    }        
    private static class SingletonContainer{        
        private static Singleton instance = new Singleton();        
    }        
    public static Singleton getInstance(){        
        return SingletonContainer.instance;        
    }        
} 

JVM內部的機制能夠保證當一個類被加載的時候,這個類的加載過程是線程互斥的。這樣當我們第一次調用getInstance的時候,JVM能夠幫我們保證instance只被創建一次,并且會保證把賦值給instance的內存初始化完畢,這樣我們就不用擔心3.2中的問題。此外該方法也只會在第一次調用的時候使用互斥機制,這樣就解決了3.1中的低效問題。最后instance是在第一次加載SingletonContainer類時被創建的,而SingletonContainer類則在調用getInstance方法的時候才會被加載,因此也實現了惰性加載。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/73967.html

相關文章

  • 雙重檢查鎖定失效分析

    摘要:雙重檢查鎖定以下稱為已被廣泛當做多線程環境下延遲初始化的一種高效手段。由于沒有對這些做出明確規定,很難說是否有效。可以在中使用顯式的內存屏障來使生效,但中并沒有這些屏障。如果改變鎖釋放的語義釋放時執行一個雙向的內存屏障將會帶來性能損失。 雙重檢查鎖定(以下稱為DCL)已被廣泛當做多線程環境下延遲初始化的一種高效手段。 showImg(http://segmentfault.com/i...

    keke 評論0 收藏0
  • Java 雙重加鎖單例 java 內存重排序特性

    摘要:關于對于重排序的講解,強烈推薦閱讀程曉明寫的深入理解內存模型二重排序。語義語義單線程下,為了優化可以對操作進行重排序。編譯器和處理器為單個線程實現了語義,但對于多線程并不實現語義。雙重加載的單例模式分析即雙重檢查加鎖。 版權聲明:本文由吳仙杰創作整理,轉載請注明出處:https://segmentfault.com/a/1190000009231182 1. 引言 在開始分析雙重加鎖單...

    HackerShell 評論0 收藏0
  • 深入理解單例模式

    摘要:總結我們主要介紹到了以下幾種方式實現單例模式餓漢方式線程安全懶漢式非線程安全和關鍵字線程安全版本懶漢式雙重檢查加鎖版本枚舉方式參考設計模式中文版第二版設計模式深入理解單例模式我是一個以架構師為年之內目標的小小白。 初遇設計模式在上個寒假,當時把每個設計模式過了一遍,對設計模式有了一個最初級的了解。這個學期借了幾本設計模式的書籍看,聽了老師的設計模式課,對設計模式算是有個更進一步的認識。...

    FuisonDesign 評論0 收藏0
  • 雙重檢查鎖定延遲初始化

    摘要:基于的雙重檢查鎖定的解決方案對于前面的基于雙重檢查鎖定來實現延遲初始化的方案指示例代碼,我們只需要做一點小的修改把聲明為型,就可以實現線程安全的延遲初始化。 雙重檢查鎖定的由來 在java程序中,有時候可能需要推遲一些高開銷的對象初始化操作,并且只有在使用這些對象時才進行初始化。此時程序員可能會采用延遲初始化。但要正確實現線程安全的延遲初始化需要一些技巧,否則很容易出現問題。比如,下...

    yvonne 評論0 收藏0
  • Java 設計模式單例模式

    摘要:在設計模式一書中,將單例模式稱作單件模式。通過關鍵字,來保證不會同時有兩個線程進入該方法的實例對象改善多線程問題為了符合大多數程序,很明顯地,我們需要確保單例模式能在多線程的情況下正常工作。 在《Head First 設計模式》一書中,將單例模式稱作單件模式。這里為了適應大環境,把它稱之為大家更熟悉的單例模式。 一、了解單例模式 1.1 什么是單例模式 單例模式確保一個類只有一個實例,...

    everfight 評論0 收藏0

發表評論

0條評論

yearsj

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<