一、什么是設計模式?
單例模式是設計模式中較為常見的一種。那么,什么是單例模式?
- 設計模式(Design Pattern)都是一些相對優秀的解決方案,很多問題都是典型的、有代表性的問題,學習設計模式,我們就不用自己從頭來解決這些問題,相當于在巨人的肩膀上,復用這些方案即可。
- 設計模式已經成為專業人士的常用詞匯,不懂不利于交流。
- 能讓你設計的系統更加專業,讓系統有更好的架構。
目的:使用設計模式是為了可重用性代碼,讓代碼更容易被他人理解,保證代碼可靠性。
二、單例模式
基本概念:
?單例模式是一種設計模式,它的目的是保證一個類只有一個實例,并提供一個全局的訪問點。使用單例模式可以避免多次創建對象,節省內存空間,同時也可以保證數據的一致性。
約定某個類,只能有唯一個對象。通過編碼技巧,讓編譯器進行強制檢査,(在類里面提前把對象創建好,并且把構造方法設為 private)
2.1 單例模式的好處
- [ 節省系統資源] :在系統中,如果有多個實例會造成資源浪費,而使用單例模式可以減少這種浪費。
- [簡化了對象訪問] :單例模式提供了一個全局的訪問點,因此可以簡化訪問過程。
2.2 懶漢模式
懶漢式單例模式:
在第一次使用時才創建單例對象。缺點是需要考慮線程安全問題。
單線程版代碼實例:
//類加載的時候不創建實例. 第一次使用的時候才創建實例.
class Singleton {private static Singleton instance = new Singleton();private Singleton() {}public static Singleton getInstance() {return instance;}
}
?上述代碼懶漢模式的實現是線程不安全的
- 線程安全問題發生在首次創建實例時。如果在多個線程中同時調用 getInstance 方法,就可能導致創建出多個實例;
- 一旦實例已經創建好了, 后面再多線程環境調用 getInstance 就不再有線程安全問題了(不再修改instance 了)
懶漢模式-多線程版
加上 synchronized 可以改善這里的線程安全問題
class Singleton {private static Singleton instance = null;private Singleton() {}public synchronized static Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}
}
懶漢模式-多線程版(改進版)
代碼在加鎖的基礎上, 做出了進一步改動:
- 使用雙重 if 判定, 降低鎖競爭的頻率.。
- 給 instance 加上了 volatile。
package single;/*** @author Zhang* @date 2024/5/717:12* @Description:*/class SingletonLazy{private static volatile SingletonLazy instance = null; //懶漢模式public static SingletonLazy getInstance(){if(instance == null){//如果對象已經有了,線程就安全了,此時就可以不加鎖了//如果對象還沒有,存在在線程不安全的風險,就需要加鎖synchronized (SingletonLazy.class){ //一旦加鎖,就可能產生阻塞if (instance == null){ //判定是否要new一個對象instance = new SingletonLazy();}}}return instance;}private SingletonLazy(){ }}public class Test2 {public static void main(String[] args) {}
}
注意理解上述代碼雙重 if 判定 / volatile:
- 理解雙重 if 判定 / volatile:加鎖 / 解鎖是一件開銷比較高的事情。 而懶漢模式的線程不安全只是發生在首次創建實例的時候,因此后續使用的時候, 不必再進行加鎖了。
- 外層的 if 就是判定下看當前是否已經把 instance 實例創建出來了。同時為了避免 “內存可見性” 導致讀取的 instance 出現偏差, 于是補充上 volatile。
2.3 餓漢模式
餓漢式單例模式:在類加載時創建單例對象。缺點是不支持延遲加載。
- 優點:單例只有在使用時才被實例化,一定程度上節約了資源 ;
- 缺點:加入synchronized關鍵字,造成不必要的同步開銷。不建議使用。
package single;/*** @author Zhang* @date 2024/5/716:58* @Description:*/class Singleton{/*** 1. 在類的內部,提供一個現成的實例* 2. 把構造方法設置為private,避免其他代碼能夠創建出實例* 通過上述方式,就強制了其他程序員在使用這個類的時候,就不會創建出多個對象了*/private static Singleton instance = new Singleton(); //這里的創建時機,是在類加載的時候(比較早的時機)--餓漢模式//通過這個方法來獲取剛剛的實例//后續如果想使用這個類的實例,都通過getInstance() 方法來獲取public static Singleton getInstance(){return instance;}//把構造方法設置為私有,此時類外面的代碼,就無法new相互這個類的對象了private Singleton(){ }}public class Test1 {public static void main(String[] args) {Singleton s1 = Singleton.getInstance();Singleton s2 = Singleton.getInstance();System.out.println(s1 == s2); //true}
}
2.4 單例模式的總結
?我們只介紹單例實現方式的餓漢模式、懶漢模式兩種方式,其他單例模式的內容可以通過網絡資源進行查閱。接下來讓我們總結一下不同單例模式的區別:
總結
?以上就是今天要講的內容,本文僅僅簡單介紹了設計模式的概念,什么是單例模式?包括懶漢模式和餓漢模式,并寫出了相應的參考代碼。最后,對不同實現方式的單例模式進行了總結。