設計模式 單例模式

2021-10-07 03:10:01 字數 3881 閱讀 6146

靜態條件問題:

還沒做好準備卻收到了通知

notify是喚醒乙個執行緒

notifyall是喚醒所有程序

(一般更推薦notify)

wait和sleep的對比[?]

這倆完全沒有關係

sleep是讓當前執行緒休眠

wait/notify機制一定程度的影響執行緒排程.

單例模式 是一種常見的"設計模式" ?
設計模式:

軟體開發中,涉及到的場景有很多

也會有很多變化(軟體開發是一件比較複雜的事情)

很多新手如果不加限制亂開發

此時往往就會陷入到很多很多的問題中

於是大佬們就把常見的場景的一些常見解決方案

整理成了乙份棋譜

後續新手只要按照棋譜來開發.此時就不會差到哪去

這份棋譜就是設計模式

**中的有些概念,不應該存在多個例項,此時應該使用單例模式來解決

保證指定的類只能有乙個例項(如果嘗試建立多個例項,直接編譯報錯)

兩種典型的方式實現單例模式:

1.餓漢模式

只要類被載入,就會立刻例項化,singleton例項

後續無論怎麼操作,只要嚴格使用getinstance,就不會出現其他的例項

剛才的new沒報錯是因為singleton類是內部類

所以類可以訪問內部類的成員的

**:

class

singleton1

// static 和 類相關, 和 例項無關~ 類在記憶體中只有乙份, static 成員也就只有乙份.

public

static singleton1 getinstance()

}public

class

ehan

}

2.懶漢模式

使用懶漢模式的時候,singleton類被載入時,不會立刻例項化

等到第一次使用這個例項的時候在例項化

如果**一整場都沒有呼叫getinstance

此時例項化的過程也就被省略掉了

這也被叫做"延時載入"

一般認為"懶漢模式"比"餓漢模式"效率更高

因為懶漢模式有很大可能是例項用不到,此時就節省了例項化的開銷

**:

class

singleton2

public

static singleton2 getinstance()

return instance;}}

public

class

lanhan

}

1. 那麼單例模式和執行緒有什麼關係呢?涉及到執行緒安全問題?

剛才這兩種單例模式的實現模式,是否是執行緒安全的?

(什麼樣的情況會導致執行緒不安全呢?)

現成的排程是搶占實質性

修改操作不是原子的

多執行緒同時修改同乙個變數

記憶體可見性…

類載入只有一次機會,不可能併發執行

對於餓漢模式來說,多執行緒同時呼叫getinstance

由於getinstance只做了一件事:讀取instance

所以相當於多個執行緒在同時讀取同乙個變數,不存在修改

所以他是執行緒安全的

對於懶漢模式來說,多執行緒同時呼叫getinstance

由於getinstance做了四件事

讀取instance內容

判斷instance內容是否為空

如果instance為null,就new例項 => 會修改instance的值

返回例項位址.

併發執行時:

執行緒1 執行緒2

讀取instance內容 讀取instance內容

判斷instance內容是否為空 判斷instance內容是否為空

如果instance為null,就new例項 如果instance為null,就new例項

返回例項位址 返回例項位址

此時這個類已經不是單例了,而是new了兩次,如果執行緒數目更多

就可能會new更多的次數.

不再符合單例模式的要求,就認為**是錯誤的

所以說懶漢模式是執行緒不安全的(涉及到兩個執行緒同時去修改同乙個變數)

如果要是已經把例項建立好了,後面再去併發呼叫getinstance就是執行緒安全的

執行緒安全的懶漢模式:

class

singleton3

public

static singleton3 getinstance()

}return instance;

}}

加鎖以後:

執行緒1:						執行緒2

加鎖 等待中..

讀取instance 等待中...

判斷instance內容是否為空 ...

為null就new instance ...

釋放鎖 獲取鎖(instance此時一定是非null)

返回 讀取instance

兩種寫法都可以,但是下面的寫法,鎖粒度更大 (鎖中包含的**越多)

就認為粒度越大

---但是當例項建立好了以後,此時就不再設計執行緒安全問題

2. 在上面的**中,哪怕例項已經建立好了,每次呼叫getinstance還是會涉及到加鎖,而這裡加鎖解鎖已經不再需要了

我們需要的是只有例項化之前呼叫的時候加鎖,後面不加鎖~

因此再次進行修改:

class

singleton3

public

static singleton3 getinstance()

}}return instance;

}}

例項化前:

執行緒1							執行緒2

讀取instancce 讀取instancce

判斷instance為空 判斷instance為空

加鎖(成功) 加鎖(失敗)

讀取instancce 等待

判斷instance為空

發現instance為空 new例項

釋放鎖返回 加鎖成功

例項化後:

執行緒1							執行緒2

讀取instancce 讀取instancce

判斷instance非空 判斷instance非空

...

3. 但是~

上面的**仍然有問題

先加鎖的執行緒在修改

後加鎖的執行緒在讀取

那麼就涉及到記憶體可見性問題,因為僅僅是讀取操作,可能被編譯器優化

所以要在instance前加volatile保證記憶體可見性

class

singleton3

public

static singleton3 getinstance()

}}return instance;

}}

最終:?

為了保證執行緒安全,涉

及到三個要點:

1.加鎖 保證執行緒安全

2.雙重 if 保證效率

3.volatil 避免記憶體可見性引來的問題

設計模式 單例模式

單例模式 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的序列生成等.但單例的使用需要謹慎,特別是在需要作負載均衡的地方,因為這種程式級的單例模式實際上只能保證在乙個應用中為單例.如果被多個應用載入,還是會...