設計模式之單例模式

  不管什麼開發中,設計模式都起着關鍵的做用,其中比較經常使用的當屬單例了,所謂單例,就是讓一個類在項目中只存在一個對象,即便用到這個類的地方不少,也只存在一個對象。可是爲何要這樣呢,爲何只建立一個對象呢,多個不也行嗎?這個就要結合實際來講了,有些對象咱們確實只須要一個,好比說線程池、緩存、硬件設備,若是多個實例就可能會致使衝突,出現運行結果不一致的現象。html

1、單例的基本框架設計模式

  固然,單例有不少種實現形式,最基本的框架大體以下:緩存

 1 /**
 2  * 普通單例:
 3  * 只使用在單一線程,多線程時可能會出現多個對象
 4  * @author 劉偉 2015/10/13
 5  */
 6 public class SimpleSingleTon {
 7     private static SimpleSingleTon instance = null;
 8 
 9     public static SimpleSingleTon getInstance() {
10         if (instance == null) {
11             instance = new SimpleSingleTon();
12         }
13         return instance;
14     }
15 
16     private SimpleSingleTon() {
17     }
18 }

  上面代碼即爲單例的一個基本的實現形式,很輕鬆就能看出在程序中首次使用這個類的代碼經過getInstance()方法就能實例化這個類從而得到類的對象,但之後再調用getInstance()時就不會實例化,而是直接得到已經存在的對象。安全

2、單例模式的優化多線程

  這段代碼在單一線程中執行是沒有問題的,但若是是在多線程中就可能會出現兩個或多個對象,試想一下若是剛好有兩個線程同時進入了getIntance()得if語句裏面,這時候就會實例化兩次SimpleSingleTon,由於首次執行getInstance()時instance是null,因此這種狀況是可能發生的。那麼怎麼避免這種狀況發生呢,可使用如下幾種方法:框架

  • 方案一:急切建立對象

  這種方法是直接在單例類裏面吧靜態變量直接實例化,這樣不管是多線程仍是單線程都能保證只有一個對象了,缺點就是會對內存形成必定的浪費。優化

 1 /**
 2  * 單例優化--急切建立對象
 3  * 
 4  * @author codingblock 2015/10/13
 5  */
 6 public class SingleTon {
 7     private static SingleTon instance = new SingleTon();
 8 
 9     public static SingleTon getInstance() {
10         System.out.println("instance:" + instance);
11         return instance;
12     }
13 
14     private SingleTon() {
15 
16     }
17 }
  • 方案二:添加同步鎖

  爲了在多線程中不讓兩個線程同時執行getInstance()方法,能夠爲此方法添加一同步鎖,這樣就能避免此狀況發生了。代碼以下:spa

 1 /**
 2  * 單例優化--添加同步鎖
 3  * 能夠在多線程中運行
 4  * @author 劉偉 2015/10/13
 5  */
 6 public class SimpleSyncSingleTon {
 7     
 8     private static SimpleSyncSingleTon instance = null;
 9     
10     public static synchronized  SimpleSyncSingleTon getInstance() {
11         if (instance == null) {
12             instance = new SimpleSyncSingleTon();
13         }
14         return instance;
15     }
16     
17     private SimpleSyncSingleTon() {
18     }
19 }

  這樣就能夠保證在多線程中也只會建立一個對象,但同步鎖是比較耗費資源的,若是在程序中頻繁地獲取對象,這樣的話效率就大大地下降了。因此說,在單例中添加同步鎖的方法比較適用於對對象獲取不是很頻繁地狀況。線程

  • 方案三:雙重檢查加鎖法

  首先須要在對象變量前面添加一個volatile關鍵字,這個是爲了通知編譯器線程安全用的。而後再getInstance檢查兩次,具體代碼以下:設計

 1 /**
 2  * 單例優化--雙重檢查加鎖法 
 3  * 能夠在多線程中運行
 4  * @author 劉偉 2015/10/13
 5  */
 6 public class CheckAgainSingleTon {
 7 
 8     private volatile static CheckAgainSingleTon instance = null;
 9 
10     public static synchronized CheckAgainSingleTon getInstance() {
11         if (instance == null) {
12             synchronized (CheckAgainSingleTon.class) {
13                 if (instance == null) {
14                     instance = new CheckAgainSingleTon();
15                 }
16             }
17         }
18         return instance;
19     }
20 
21     private CheckAgainSingleTon() {
22     }
23 }

  經過這個方法程序在獲取對象時不管怎麼樣都只會進入加鎖區一次,例如最開始兩個線程在競爭時,其中一個線程進入了加鎖後建立了對象,之後全部的進程在執行getInstance方法時直接判斷instance非null,就能直接返回對象了,不須要再進入加鎖區了。這樣即便程序頻繁地獲取對象也不會再進入加鎖區了,相對第二種方法就大大節省了資源。

  本文連接:http://www.cnblogs.com/codingblock/p/4876122.html

  聲明:本文歡迎任何形式的轉載,但請務必保留本文連接並告知本人,謝謝!

相關文章
相關標籤/搜索