目錄
- 前言
- 1.概念
- 2. 實現
- 3. 比較和改進
- 總結
前言
本篇文章來介紹單例模式,并講述在保證線程安全的前提下,單例模式的寫法。
1.概念
單例模式是一種設計模式,可以說是寫代碼的一種模板,如果在一些固定的場景下按照設計模式進行寫代碼,寫出來的代碼一定不會很差。
設計模式有非常多種,這里就介紹單例模式這一種。
單例指的是單個實例,在一些場景中,我們希望一個類只能有唯一的實例,我們就可以使用單例模式這種設計模式。
2. 實現
下面介紹如何在Java中實現單例模式,單例模式有很多種實現方法,在這里我們就介紹兩種最常用的:餓漢式和懶漢式。
餓漢式是先創建一個靜態的實例,通過getInstance方法來獲取這個唯一的實例,下面看例子:
//單例模式之餓漢式
class Singleton{//先創建一個靜態的實例private static Singleton instance = new Singleton();public static Singleton getInstance(){return instance;}private Singleton(){//私有化構造方法}
}public class Demo23 {public static void main(String[] args) {Singleton s1 = Singleton.getInstance();Singleton s2 = Singleton.getInstance();System.out.println(s1 == s2); // true}
}
注意,要將構造方法私有化,來防止外部自行創建新的實例。
懶漢式則是在第一次調取getInstance方法時,才會創建實例,下面看示例:
//單例模式之懶漢式
class SingletonLazy {private static SingletonLazy instance;private SingletonLazy() {//私有化構造方法}public static SingletonLazy getInstance() {if (instance == null) {instance = new SingletonLazy();}return instance;}
}public class Demo24 {public static void main(String[] args) {SingletonLazy s1 = SingletonLazy.getInstance();SingletonLazy s2 = SingletonLazy.getInstance();System.out.println(s1 == s2); // true}
}
3. 比較和改進
如果我們在多線程條件下調用getInstance,不難發現,懶漢模式線程不安全,因為在多個線程調用getInstance時,可能會判定到好幾次instance == null,這樣會導致創建好幾個不同的實例。在餓漢模式下,由于已經提前創建好實例,調用getInstance只會返回這個實例,所以線程安全。
下面對懶漢模式進行改進,保證其線程安全:
//單例模式之懶漢式
class SingletonLazy {private static volatile Object locker = new Object();private static SingletonLazy instance;private SingletonLazy() {//私有化構造方法}public static SingletonLazy getInstance() {if (instance == null) {synchronized (locker){if (instance == null) {instance = new SingletonLazy();}}}return instance;}
}
對實例化對象進行加鎖,由于每次一個線程都要先加鎖,操作過于繁瑣,所以在外層再添加一個判斷條件,判斷instance是否被實例化,如果實例化則直接返回instance,不需要再進行加鎖判斷,在此之后,還要給locker加上volatile關鍵字,防止編譯器優化,這里的編譯器優化是“指令重排序”,而進行優化之后,多線程進行操作的時候會出現問題,導致instance還沒有初始化就被返回,這是指令重排序而造成的線程安全問題。
總結
這篇文章簡單介紹了線程安全模式下單例模式的寫法,希望對大家有所幫助。