1.什么是單例模式
2.經典單例模式實現
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()
有可能被多個線程同時訪問,這時就會有可能 創建出兩個以上的實例對象。這就要考慮要線程安全的問題了,解決問題就是在獲取實例方法處加一個同步鎖,這樣就能輕松地解決線程并發的問題了。
public static synchronized MyInstance getMyInstance(){ //加同步鎖關鍵字synchronized,這樣在有線程訪問這個方法時,其它線程只能等待當前線程訪問結束才能訪問這個方法。 if(myInstance==null){ //這里的方法只執行了一次,生成了一個唯一的類對象 myInstance=new MyInstance(); }
4.多線程下同步所造成的性能問題
如果將獲取實例的方法進行同步的話,會造成程序執行的效率大大地下降,而且單例對象生成只要調用一次方法即可,之后每次調用這個方法時,同步都是一種累綴,有可能會拖垮程序的性能。
當然如果你的程序對于性能的要求并不是很高的話,用同步的方法獲取單例是最簡單而有效的。
為保證程序的性能并且又不會出現并發的問題,可以使用另一種生成單例對象的模式,叫做餓漢式單例模式(eagerly instantiaze)
public class MyInstance{ //第一步:私有化構造器 private MyInstance(){} //第二步:聲明一個全局靜態變量來記錄自身實例的對象,并進行實例化 private static MyInstance myInstance=new MyInstance(); //第三步:提供一個外部可訪問的靜態公開方法,來獲得該類的唯一實例 public static MyInstance getMyInstance(){ return myInstance; }
這個模式使JVM在加載這個類時會馬上創建唯一的單例對象,這樣就能保證任何線程訪問靜態單例變量myInstance時,單例對象一定被實例化過了。
5.利用雙重檢查加鎖來提升性能
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 設計模式》
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對VeVb武林網的支持。
新聞熱點
疑難解答
圖片精選