設計模式 單例模式

2021-08-21 10:33:10 字數 1638 閱讀 2900

單例分為懶漢、餓漢模式。前者的實現比較多,但用於應用中不是必須使用的物件。後者實現簡單。以下對比較成熟的實現方式做些介紹。

一、懶漢

1.雙重校驗鎖

public class singletondoublesyn 

public static singletondoublesyn getinstance()}}

return instance;

}}

這裡需要注意3點:

(1)、instance變數要加volatile關鍵字,為了防止jvm重排序。

編譯器會將這段** instance = new singletondoublesyn();//2 編譯成3句jvm指令:

memory = allocate(); // 1   給instance物件分配記憶體

init(memory);             // 2   初始化剛剛分配的記憶體

instance = memory;  // 3    將分配的記憶體位址賦值到instance中

不過這2、3兩條語句的執行順序是不確定的,會在編譯時指令重排序,如下所示:

memory = allocate(); // 1   給instance物件分配記憶體

instance = memory;  // 3    將分配的記憶體位址賦值到instance中

init(memory);             // 2   初始化剛剛分配的記憶體

執行緒a執行到3的位置,此時恰好切換到執行緒b,b先判斷instance == null,返回false,那此時b執行緒拿到的是為完成初始化的instance物件。

這一情況在變數前加上volatile可以避免。

(2)、因為絕大多數對instance的訪問是讀,因此只有在instance==null是才需要執行緒同步。

(3)、將構造方法私有化,保證單例。

2.靜態內部類

public class singletonbyinnerclass 

private static class singletonholder

public static singletonbyinnerclass getinstance()

}

這裡通過jvm的類載入機制(jvm對載入類時,做了同步機制),巧妙地避免了執行緒間的競爭。

宣告乙個變數不會觸發jvm載入對應類,而當訪問了類靜態方法和靜態變數時,會觸發jvm載入類,類載入完成後會執行由編譯器根據類中static變數,static方法,static塊生成的init()方法,來初始化類。

不明白靜態內部類中的變數為何要用final修飾?

jvm在對.class檔案做了合法校驗後,會在記憶體中(方法區)開闢一塊區域,用以存放類變數,開闢完成後,會對新開闢的記憶體區域「清零」。如果乙個變數被final修飾,該變數就在此時被賦值;如果沒有final修飾,他會在對類的初始化中被賦值。無論哪種都能保證賦值,並不會被提前發布(不安全發布)。為什麼要加final?

二、餓漢

public class singletonhungry 

public static singletonhungry getinstance()

}

設計模式 單例模式

單例模式 singleton pattern 是乙個比較簡單的模式,其定義如下 ensure a class has only one instance,and provide a golbal point of acess to it.確保某乙個類只有乙個例項,而且自行例項化並且向整個系統提供這個...

設計模式 單例模式

class testsingleton static public function instance return self testsingleton private function clone public function setsinvar sinvar public function ...

設計模式 單例模式

單例模式的目的是保證類在系統中只被例項化一次,由該唯一的例項來為系統提供服務.單例模式主要用於保證服務的統一,比如獲取統一的編號服務,模仿oracle的序列生成等.但單例的使用需要謹慎,特別是在需要作負載均衡的地方,因為這種程式級的單例模式實際上只能保證在乙個應用中為單例.如果被多個應用載入,還是會...