【Java設計模式】單例模式

來源:互聯網
上載者:User

標籤:


### 1. 概述
> 單例模式是確保某一個類中有且只有一個執行個體。

----------
### 2. 餓漢式單例
``` java
public class SingletonInstance {
private static SingletonInstance mInstance = new SingletonInstance();
// 預設私人構造方法
private SingletonInstance(){}
// 靜態Factory 方法
public static SingletonInstance getInstance(){
return mInstance ;
}
}
```
在餓漢式單例中,靜態變數會在私人構造方法中初始化,這時候唯一的執行個體就被建立出來了,餓漢式主要使用到的是**空間換時間**的思想,在類還在載入的時候,對象執行個體便已經建立好了。

----------

### 3. 懶漢式單例
```java
public class SingletonInstance {
private static SingletonInstance mInstance = null;
// 私人預設構造方法
private SingletonInstance(){}
// 靜態Factory 方法
public static synchronized SingletonInstance getInstance(){
if(mInstance == null){
mInstance = new SingletonInstance();
}
return mInstance;
}
}
```
對於懶漢式單例的處理,使用了``synchronized``參數修飾Factory 方法,用來在多線程環境中解決同步問題,懶漢式主要是使用到的是**時間換空間**的思想,在擷取執行個體的時候進行判斷,只有在需要的時候才去建立對象,節省記憶體空間,但是缺點就是實現的方式是安全執行緒的,這樣會降低訪問的速度。

----------
### 4. 雙重加鎖單例
```java
public class SingletonInstance {
private volatile static SingletonInstance mInstance = null;
private SingletonInstance(){}
public static SingletonInstance getInstance(){
//先檢查執行個體是否存在,如果不存在才進入下面的同步塊
if(mInstance == null){
//同步塊,安全執行緒的建立執行個體
synchronized (SingletonInstance .class) {
//再次檢查執行個體是否存在,如果不存在才真正的建立執行個體
if(mInstance == null){
mInstance = new SingletonInstance ();
}
}
}
return mInstance;
}
}
```
雙重加鎖機制指的是,在每次進入``getInstance``方法先不同步,而是進入方法後,先檢查執行個體是否存在,如果不存在才進行下面的同步塊,這屬於第一重檢查,進入同步塊過後再檢查執行個體是否存在,如果不存在,就在同步的情況下建立一個新的執行個體,這屬於第二重檢查。這樣便只需要同步一次,並減少了在多次同步情況下進行判斷浪費的時間。
這種實現方式會使用到**volatile**關鍵字,意思是被**volatile**修飾的變數的值,不會被本地線程緩衝,所有對該變數的讀寫都是直接操作共用記憶體,從而保證線程正確的處理該變數。
> **volatile**關鍵字在**JDK5**之前的版本中加鎖失敗,注意之。而且**volatile**關鍵字會屏蔽掉虛擬機器中的一些必要的代碼最佳化,因此雖然能實現雙重檢查加鎖機制的單例,但並不建議大量採用。

那有什麼方案可以既能達到消極式載入,又能實現安全執行緒的目的呢?

-----
### 5. Lazy Initialization Holder Class模式
```java
public class SingletonInstance {

private SingletonInstance(){}
/**
* 類級的內部類的執行個體與外部類的執行個體沒有綁定關係,而且只有被調用到時才會裝載
*/
private static class SingletonHolder{
/**
* 靜態初始化,由JVM來保證安全執行緒
*/
private static SingletonInstance mInstance = new SingletonInstance();
}
public static SingletonInstance getInstance(){
return SingletonHolder.mInstance;
}
}
```
如果只是想簡單的實現安全執行緒的單例,可以使用之前的**餓漢式**方式。但是缺點就是會在類裝載的時候初始化對象,造成空間的浪費。
那麼只要解決了類載入時自動初始化對象的問題,便可以解決問題。因此可以採用類級內部類的方式去實現,這樣的話,只有在需要的時候才會建立對象執行個體,也達到了消極式載入和安全執行緒的目的。
從實現過程來看,但調用`getInstance`方法時,它會讀取`SingletonHolder.mInstance`,從而初始化,在這個類被裝載的時候,也會初始化靜態成員,而由於靜態域的特性,只會初始化一次,並且由JVM來保證安全執行緒。
>- 什麼是類級內部類?
被`static`修飾的成員內部類才是類級內部類,如果沒有被`static`修飾則被稱為對象內部類,而且類級內部類與外部類對象不存在依賴關係,只有在第一次使用的時候才會被調用。
>- 多線程預設同步鎖知識?
在多線程開發中,我們主要使用`synchronized`來對互斥鎖進行同步控制,但是某些情況下JVM已經為我們進行了同步控制了,主要有:
1. 靜態初始化方法初始化資料時;
2. 訪問`final`欄位時;
3. 在建立線程之前建立對象時;
4. 線程可以看見要處理的對象時;

----------
### 6. 枚舉式單例
```java
public enum SingletonInstace{
// 定義一個枚舉元素,它代表了一個執行個體
mInstance;
// 單例的操作
public void singletonOperation(){

}
}
```
使用枚舉的方式既使得代碼簡潔,而且也由JVM來保證序列化機制,防止多次執行個體化,是最佳的實現單例的方式。

【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.