您好,登錄后才能下訂單哦!
單例模式也叫做單肩模式,也是一種創建型模式,是我們日常開發中最常使用的一種設計模式,經常被用來封裝一些工具類,例如數據庫連接等。
單例模式的定義:
單例模式,是一種常用的軟件設計模式。在它的核心結構中只包含一個被稱為單例的特殊類。通過單例模式可以保證系統中一個類只有一個實例。即一個類只有一個對象實例
單例模式分為以下幾種:
①餓漢單例模式
②懶漢單例模式
③IoDH單例模式
④枚舉單例模式
下面我們一一的進行介紹:
1.首先是餓漢單例模式,顧名思義“餓漢”,代表急著“吃飯”(這里的飯應該是指的實例對象),所以很早就創建出來。不多說,上代碼:
package singleton; public class HungrySingletonP { private static HungrySingletonP instance=new HungrySingletonP(); public HungrySingletonP(){} public static HungrySingletonP getInstance(){ return instance; } }
這段代碼很形象的體現了餓漢模式。
這種方法在類加載的時候就已經實例化了(只創建唯一的實例),所以不存在線程上的一些問題。但是,也因為如此如果有太多的單例,且這些實例不經常使用那么久會造成對內存的浪費。
2.懶漢模式,同樣什么叫做懶漢模式?一個懶惰的人,只有去吃飯的時候才會去刷碗(昨天用過的臟碗),即:只有當用到對象的時候才去創建對象,來上代碼:
package singleton; public class LasySingletonV1 { private static LasySingletonV1 instance; public LasySingletonV1(){} public static LasySingletonV1 getInstance(){ if(instance==null){ return new LasySingletonV1(); }else return instance; } }
上面的這段代碼是懶漢模式,當我們不需要實例的時候,它不會創建實例,只有需要實例的時候,才會創建,節省空間。
但是,我們不推薦使用,因為我們原來的設計理念是:當需要的時候(并且instance為空)創建實例,當已經創建過后,如果還需要實例,則判斷instance是否為空,因為前邊已經創建過了,不為空,所以直接返回之前已經創建的實例。
以上的想法是很好的,但是它是線程不安全的。因為:當有多個線程同時調用這個方法時,因為同時判斷實例為空,所以會創建很多個實例,這不符合單例模式的設計理念(一個類只有一個實例對象)。
所以我們需要對它進行改進,因為它會異步創建多個實例,多以我們很容易就能想到,在getInstance方法之前加上synchronized進行同步:
package singleton; public class LasySingletonV2 { private static LasySingletonV2 instance; public LasySingletonV2(){} public synchronized LasySingletonV2 getInstance(){ if(instance==null){ return new LasySingletonV2(); }else return instance; } }
上面這樣,就不會創建多個實例對象符合單例模式的概念。
但是上面這樣的設計使得我們每次需要目標實例的時候都要排隊等待,假設有很多線程都在調用這個getInstance方法,那么就會陷入很長時間的等待,大大降低的程序的效率。
所以我們還要對程序進行一定的修改,如果我們創建一個
package singleton; public class LasySingletonV3 { private static LasySingletonV1 instance; public LasySingletonV3(){} public LasySingletonV3 getInstance(){ if(instance==null){ synchronized(LasySingletonV3.class){ if(instance==null){ return new LasySingletonV3(); } } } return instance; } }
以上的方法是懶漢模式的完整版本,我們來仔細分析一下:
當有多個線程第一次調用這個方法的時候,都滿足instance為空,來到下一步,先獲得鎖的線程進入下一步繼續判斷是否為空,為空,然后創建實例返回實例。
沒有獲得鎖的線程一直等待到獲得鎖的線程釋放鎖,當在等待的線程獲得鎖的時候進入下一步,還要進行判斷instance是否為空,但是這個時候instance已經不為空了,因為前面的線程已經創建了實例,所以返回已經創建好的實例。
以上是第一批調用getInstance方法的線程,當后續的線程調用這個方法的時候就不用進行鎖的獲取了和釋放了,因為第一步已經判斷instance不為空,直接返回instance實例。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。