Java中如何?單例模式

來源:互聯網
上載者:User

標籤:單例   java   

Java中,單例模式通常有2種分類餓漢模式和懶漢模式。

餓漢模式指的是單例執行個體在類裝載時就被建立了。

懶漢方式值的是單例執行個體在首次使用時才被建立。

無論是餓漢模式還是懶漢模式,都是用了一個靜態成員變數來存放真正的執行個體。並且私人化建構函式,防止被外部執行個體化。

單例(餓漢模式)代碼:

public class Singleton {    private final static Singleton INSTANCE = new Singleton();    //私人化構造方法,防止被執行個體化       private Singleton() {    }    public static Singleton getInstance() {        return INSTANCE;    }}


單例懶漢模式代碼,注意靜態欄位聲明的時候,有一個volatile關鍵字,並且代碼中兩次判斷是否是null,這種雙重檢測的機製為了應對多線程環境。

public class Singleton {    private static volatile Singleton INSTANCE = null;    //私人化構造方法,防止被執行個體化    private Singleton() {    }    //雙重檢測    public static Singleton getInstance() {        if (INSTANCE == null) { //①            synchronized (Singleton.class) { //②                if (INSTANCE == null) { //③                    INSTANCE = new Singleton(); //④                }            }        }        return INSTANCE;    }}


需要注意的是,即使這種Doublecheck在C++中有效,但對JAVA5之前的代碼還是有一點問題的。

原因在於,編譯器會最佳化代碼,可能導致指派陳述式亂序執行,上述代碼中,如果有2個線程A,B。A線程已經進入4位置,當4位置的代碼執行時,需要注意 INSTANCE = new Singleton()這個行代碼不是一個原子操作。

JVM可能在完成Singleton類的構造方法之前,會先把一塊還未初始化完成的記憶體位址先分配給INSTANCE,而此時如果線程B進入1位置,會認為INSTANCE已經存在,從而返回了一個未初始化完成的記憶體塊,這可能導致程式崩潰。正是由於是先給INSTANCE賦值在初始化記憶體塊,還是先初始化記憶體塊再複製給INSTANCE,這個順序無法保證,所以這種機制會出現問。所以在JAVA5之後,擴充了 volatile關鍵字,確保一個變數寫入和讀取操作的順其不會被編譯器最佳化成亂序,volatile變數也不會被緩衝到cpu寄存器中,保證了其讀取的一致性。

這和C#中的volatile的關鍵字是一樣的作用。

除了上面2中常見的方法之外,還有其他方法。比如下面一種比較經典的實現方法,使用一個內部類,JVM自身保證了自身安全,這個模式也是在《Effective Java》這本書中推薦的,這種方式不依賴於java版本。

public class Singleton {    private Singleton() {    }    public static final Singleton getInstance() {        return InnerClass.INSTANCE;    }    private static class InnerClass {        private static Singleton INSTANCE = new Singleton();    }}


但在JAVA5之後,最簡單的單例實現方法是使用enum類型。

enum關鍵字是JAVA5中新增的,它和class,interface一樣,也是一種資料類型。可以把它看成是一種特殊的類。可以在enum內部實現構造方法,欄位,方法等,還可以實現介面。不過也有一些限定,枚舉類中的構造器,預設為private修飾,且只能使用private。枚舉類的所有執行個體必須在類中的第一行顯式列出,否則這個枚舉類不可能產生執行個體。JVM保證了這個每個枚舉值只被初始化一次。正是由於這樣一個特點,我們可以用如下代碼可以實現單例。

public enum Singleton {INSTANCE;    public void dosth(String arg) {        // 邏輯代碼    }}


上述單例中,Singleton.INSTANCE就表示了一個單例。非常簡單高效。

注意Java中enum關鍵字和C#中的enum,差別很大,C#中不能使用這種方式。

本文出自 “一隻部落格” 部落格,請務必保留此出處http://cnn237111.blog.51cto.com/2359144/1641192

Java中如何?單例模式

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.