本篇文章給大家?guī)砹岁P(guān)于java的相關(guān)知識(shí),其中主要介紹了關(guān)于單例模式的相關(guān)問題,指一個(gè)類只有一個(gè)實(shí)例,且該類能自行創(chuàng)建這個(gè)實(shí)例的一種模式,下面我們一起來看一下,希望對大家有幫助。
推薦學(xué)習(xí):《java視頻教程》
單例模式:
首先在Java中有23種設(shè)計(jì)模式:
- 創(chuàng)建型模式: 工廠方法模式、抽象工廠模式、單例模式、建造者模式、原型模式
- 結(jié)構(gòu)型模式: 適配器模式、裝飾者模式、代理模式、外觀模式、橋接模式、組合模式、享元模式
- 行為型模式::策略模式、模板方法模式、觀察者模式、迭代子模式、責(zé)任鏈模式、命令模式、備忘錄模式、狀態(tài)模式、訪問者模式、中介者模式、解釋器模式。
1、什么是單例模式:
定義:
指一個(gè)類只有一個(gè)實(shí)例,且該類能自行創(chuàng)建這個(gè)實(shí)例的一種模式??梢员苊庖虼蜷_多個(gè)任務(wù)管理器窗口而造成內(nèi)存資源的浪費(fèi),或出現(xiàn)各個(gè)窗口顯示內(nèi)容的不一致等錯(cuò)誤。比如咱們電腦是不是只能打開一個(gè)任務(wù)管理器?對吧,這就是為了防止資源浪費(fèi)和其他錯(cuò)誤。
項(xiàng)目中一般可以通過單例模式來獲取同一個(gè)對象來調(diào)用工具方法,這樣的好處是節(jié)約內(nèi)存資源,我沒有必要?jiǎng)?chuàng)建多個(gè)不同的對象,因?yàn)檫@樣消耗內(nèi)存資源
簡而言之: 單例就是程序只有一個(gè)實(shí)例,該類負(fù)責(zé)創(chuàng)建自己的對象,同時(shí)要確保只有一個(gè)對象創(chuàng)建
單例模式的特點(diǎn):
- 構(gòu)造器私有
- 持有自己類型的屬性
- 對外提供獲取實(shí)例的靜態(tài)方法
單例模式的結(jié)構(gòu)圖:
2、單例模式的優(yōu)缺點(diǎn):
優(yōu)點(diǎn):
- 減少了內(nèi)存的開銷
- 避免對資源的多重占用
- 設(shè)置全局訪問點(diǎn),可以優(yōu)化和共享資源的訪問
缺點(diǎn)(參考自互聯(lián)網(wǎng)):
- 一般沒有接口,擴(kuò)展困難。如果要擴(kuò)展,則除了修改原來的代碼,沒有第二種途徑,違背開閉原則
- 在并發(fā)測試中,單例模式不利于代碼調(diào)試。在調(diào)試過程中,如果單例中的代碼沒有執(zhí)行完,也不能模擬生成一個(gè)新的對象
- 單例模式的功能代碼通常寫在一個(gè)類中,如果功能設(shè)計(jì)不合理,則很容易違背單一職責(zé)原則
看一張單例模式的思維導(dǎo)圖:
3、懶漢模式(比較常用)
懶漢模式特征是延遲初始化,在調(diào)用方法獲取實(shí)例的時(shí)候才會(huì)實(shí)例化對象
線程不安全,嚴(yán)格意義上來說不是單例模式,優(yōu)勢是在獲取實(shí)例才會(huì)創(chuàng)建對象因此更節(jié)省內(nèi)存開銷
Demo:
public class SingLeton { //1、有自己類型的屬性 private static SingLeton instance; //2、構(gòu)造器私有化 private SingLeton(){} //3、對外提供獲取實(shí)例的靜態(tài)方法 public static SingLeton getInstance(){ if (instance == null){ instance = new SingLeton(); } return instance; }}
測試類:
public class Test { public static void main(String[] args) { //判斷是否產(chǎn)生的是同一個(gè)對象 SingLeton s1 = SingLeton.getInstance(); SingLeton s2 = SingLeton.getInstance(); System.out.println(s1 == s2); }}
輸出:
true
注意:
關(guān)于懶漢模式線程非安全
現(xiàn)在知道懶漢模式的線程是非安全的,那么就需要使用鎖(synchronized )來同步:
/** * 保證 instance 在所有線程中同步 */public class SingLeton2 { //1、有自己類型的屬性 private static volatile SingLeton2 instance ; //2、構(gòu)造器私有化 private SingLeton2() { } public static synchronized SingLeton2 getInstance() { //getInstance 方法前加同步 if (instance == null) { instance = new SingLeton2(); } return instance; } }
如果是寫多線程,則不要?jiǎng)h除上例代碼中的關(guān)鍵字 volatile 和 synchronized,否則將存在線程非安全的問題。如果不刪除這兩個(gè)關(guān)鍵字就能保證線程安全,但是每次訪問時(shí)都要同步,會(huì)影響性能,且消耗