1.什么是單例模式
- 生成一個獨一無二的,保證任何時刻一個類只有一個實例的模式
- 確保一個類只有一個實例,并提供一個全局訪問點
- 可以在需要時才創建對象,避免了全局變量在程序啟動時就得創建對象的缺點。
2.經典單例模式實現
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public class myinstance{ //第一步:私有化構造器,只有類自身才能調用構造器外部類不能夠直接new出這個類的實例對象 private myinstance(){} //第二步:聲明一個全局靜態變量來記錄自身實例的對象,也是私有的,限制其它外部類訪問 private static myinstance myinstance; //第三步:提供一個外部可訪問的靜態公開方法,來獲得該類的唯一實例 public static myinstance getmyinstance(){ //第四步:進行判斷自身類對象如果為空,則創建一個實例 if (myinstance== null ){ //這里的方法只執行了一次,生成了一個唯一的類對象 myinstance= new myinstance(); } //第五步:如果不為空,則返回該類對象,故由始至終,該類對象只初始化過一次,只有一個對象存在,這就是單例模式 return myinstance; } } |
3.經典模式存在的缺陷
這種經典模式也稱之為懶漢式單例模式(lazy instantiaze),因為它是延遲化實例化的,即如果我們不需要這個實例,則它永遠不會被初始化,只有在調用過一次實例化方法后,才會被創建出對象。
在多線程的情況下可能會產生并發問題,因為獲取單例的方法getmyinstance()
有可能被多個線程同時訪問,這時就會有可能 創建出兩個以上的實例對象。這就要考慮要線程安全的問題了,解決問題就是在獲取實例方法處加一個同步鎖,這樣就能輕松地解決線程并發的問題了。
1
2
3
4
5
6
|
public static synchronized myinstance getmyinstance(){ //加同步鎖關鍵字synchronized,這樣在有線程訪問這個方法時,其它線程只能等待當前線程訪問結束才能訪問這個方法。 if (myinstance== null ){ //這里的方法只執行了一次,生成了一個唯一的類對象 myinstance= new myinstance(); } |
4.多線程下同步所造成的性能問題
如果將獲取實例的方法進行同步的話,會造成程序執行的效率大大地下降,而且單例對象生成只要調用一次方法即可,之后每次調用這個方法時,同步都是一種累綴,有可能會拖垮程序的性能。
當然如果你的程序對于性能的要求并不是很高的話,用同步的方法獲取單例是最簡單而有效的。
為保證程序的性能并且又不會出現并發的問題,可以使用另一種生成單例對象的模式,叫做餓漢式單例模式(eagerly instantiaze)
1
2
3
4
5
6
7
8
9
|
public class myinstance{ //第一步:私有化構造器 private myinstance(){} //第二步:聲明一個全局靜態變量來記錄自身實例的對象,并進行實例化 private static myinstance myinstance= new myinstance(); //第三步:提供一個外部可訪問的靜態公開方法,來獲得該類的唯一實例 public static myinstance getmyinstance(){ return myinstance; } |
這個模式使jvm在加載這個類時會馬上創建唯一的單例對象,這樣就能保證任何線程訪問靜態單例變量myinstance時,單例對象一定被實例化過了。
5.利用雙重檢查加鎖來提升性能
- 首先檢查實例是否已經創建了,如果沒有才進行同步獲取實例的方法,這樣就保證了實例方法只會在第一次獲取實例時會同步。
- 這里要用到一個關鍵字volatile,此關鍵字確保了當實例變量myinstance被初始化成實例對象時,多個線程能正確地處理實例變量。注意,這個關鍵字只有在java1.5及以上的版本才會對雙重檢查加載生效。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
public class myinstance{ //用關鍵字volatile修飾實例變量 private volatile static myinstance myinstance; //私有化構造器 private myinstance(){} public static myinstance getmyinstance(){ //第一次檢查實例是否存在 if (myinstance== null ){ //如果不存在則進入同步區塊 synchronized (myinstance. class ){ if (myinstance== null ){ //第二次檢查,如果不為空才真正創建實例對象 myinstance= new myinstance(); } } } //如果不為空,則直接返回該類對象 return myinstance; } } |
單例模式的所有情況都已經總結完畢,一開始以為單例模式應該是所有設計模式中最簡單易懂的了,沒想到看到四人幫的headfirst設計模式后發現還有這么多門道,真的是學無止境。
注:以上所有內容皆總結自《headfirst 設計模式》
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對服務器之家的支持。如果你想了解更多相關內容請查看下面相關鏈接
原文鏈接:https://blog.csdn.net/pigdreams/article/details/53232731