單例模式的7種寫法

2021-10-01 22:37:04 字數 3737 閱讀 6062

設計模式(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...