設計模式(design pattern)一共有23種,而單例模式(singleton pattern)是 其中最簡單的設計模式之一,這種模式涉及到乙個單一的類,該類負責建立自己的物件,同時確保只有單個物件被建立。單例模式有很多種寫法,下面我們介紹一下常見的7種寫法。單例模式有幾個注意點:
常見的單例模式主要分為懶漢式、餓漢式,這兩種又衍生出了很多種寫法。還有一種寫法是單例的列舉模式,本文將逐一介紹。
懶漢式,顧名思義就是例項在用到的時候才去建立,「比較懶」,用的時候才去檢查有沒有例項,如果有則返回,沒有則新建。它有執行緒安全和不安全的兩種寫法,下面我們由淺入深,逐一討論。
這是一種比較常規和簡單的寫法,值得注意的是它的構造方法是私有的,乙個執行緒不安全的寫法,多執行緒環境下,可能執行多次就會new多次,會產生一定的影響。
@slf4j
@notthreadsafe
public
class
singletondemo1
//單例物件
private
static singletondemo1 instance = null;
//靜態工廠方法獲取物件
public
static singletondemo1 getinstance()
return instance;
}}
@slf4j
@threadsafe
@notrecommend
public
class
singletondemo3
//單例物件
private
static singletondemo3 instance = null;
//靜態工廠方法獲取物件
//加上synchronized關鍵字
public
static
synchronized singletondemo3 getinstance()
return instance;
}}
懶漢模式的另一種寫法是雙重同步鎖**模式,又稱雙重檢測機制 (dcl),如下:
@slf4j
@notthreadsafe
public
class
singletondemo4
//單例物件
private
static singletondemo4 instance = null;
//靜態工廠方法獲取物件
public
static singletondemo4 getinstance()
}}return instance;
}}
我們在getinstance()裡面又加了乙個雙重檢測校驗,這種方式在單執行緒下面沒有問題,而在多執行緒情況下就會不安全了,一般情況下它的執行順序為:
memory = allocate() 分配物件的記憶體空間
ctorinstance()初始化物件
instance = memory 設定instance指向放分配的記憶體
由於可能會出現指令重排的情況,由於jvm和cpu優化,發生了指令重排,執行順序就可能為:1、3、2。
例如:兩個執行緒,執行緒a、b同時呼叫這個getinstance方法,a執行到了下面a的位置,而b執行到了下面b的位置,如果按照上面說的指令重排的1,3,2順序 a執行了3,而b執行緒來了之後,發現a執行緒已經有值了(但是它還沒執行2對其進行初始化操作),然後直接返回了,就會出問題了。此刻,我們需要在當前這種情況下,防止指令重排,就引出了volatile關鍵字。
限制它產生指令重排,用volatile關鍵字,如下:
@slf4j
@threadsafe
public
class
singletondemo5
/** * 1、memory = allocate() 分配物件的記憶體空間
* 2、ctorinstance()初始化物件
* 3、instance = memory 設定instance指向放分配的記憶體
*///單例物件 volatile + 雙重檢測機制 -> 禁止指令重排
private
static
volatile singletondemo5 instance = null;
//靜態工廠方法獲取物件
public
static singletondemo5 getinstance()
}}return instance;
}}
惡漢模式它在類裝載使用時進行建立(能保證執行緒安全),同時也會引入乙個缺點,就是如果類的構造方法中存在著過多的處理,會導致這個類載入的時候特別慢。
@slf4j
@threadsafe
public
class
singletondemo2
//單例物件
private
static singletondemo2 instance =
newsingletondemo2()
;//靜態工廠方法獲取物件
public
static singletondemo2 getinstance()
}
通過靜態**塊的方式來例項化類物件,這裡有點需要注意,就是在寫靜態域或者靜態**塊的時候,我們要注意順序,如下面1和2順序不能顛倒,顛倒了之後他們的執行結果會有所不同。
@slf4j
@threadsafe
public
class
singletondemo6
//單例物件
//當我們在寫靜態域或者靜態**塊的時候,我們要注意順序,如下面1和2順序不能顛倒,
//他們的執行結果會有所不同
//1private
static singletondemo6 instance = null;
//2static
//靜態工廠方法獲取物件
public
static singletondemo6 getinstance()
public
static
void
main
(string[
] args)
}
說實話,這種方式用的比較少,但是還是比較推薦的一種寫法,一來它是執行緒安全的。它相比於我們的懶漢模式在安全性方面得到了保證,它相比於餓漢模式,在實際呼叫的時候才做初始化
@slf4j
@threadsafe
@recommend
public
class
singletondemo7
public
static singletondemo7 getinstance()
private
enum singleton
public singletondemo7 getinstance()
}}
本文總結了7種單例模式的具體寫法,有淺入深。從最簡單的懶漢模式入手,引出了執行緒安全的實現方式。從dcl的懶漢模式的cpu指令重排,又引入了volitate關鍵字。此外,還講了惡漢模式的常規寫法,以及通過靜態**塊的寫法。最後,舉了比較推薦的列舉方式的單例模式。
參考:
單例模式的7種寫法
在介紹單例模式的寫法之前,我們有必要了解一下什麼是單例模式。單例模式是一種常用的軟體設計模式,在他的核心結構中只包含乙個被稱為 單例的特殊類。通過單例模式可以保證系統只有乙個例項而且該例項易於外界訪問,從而方便對例項個數的控制並節約系統資源。如果希望在系統中某個類的物件只能存在乙個,單例模式是最好的...
單例模式的7種寫法
program singleton description 懶漢模式,單例例項在第一次使用時進行建立,非執行緒安全 author mr.superbeyone create 2018 09 30 09 15 public class singletondemo1 單例物件 private stati...
java單例模式的7種寫法
很不錯。懶漢 2種,執行緒安全和執行緒不安全 餓漢 classloader,和static塊變種 雙重校驗鎖,列舉和靜態內部類。幾種之間的區別就是為了避免不同環境下的缺陷。下面就列舉型別的單例模式說明 package com.zoer.src public enum singletonexample...