這篇文章主要為大家展示了“Java中單例模式的示例分析”,內(nèi)容簡(jiǎn)而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(lǐng)大家一起研究并學(xué)習(xí)一下“Java中單例模式的示例分析”這篇文章吧。
創(chuàng)新互聯(lián)自2013年起,先為合江等服務(wù)建站,合江等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢(xún)服務(wù)。為合江企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問(wèn)題。懶漢模式與餓漢模式
懶漢模式就是懶加載,用到的時(shí)候去加載,存在線程安全問(wèn)題,需要手動(dòng)地加鎖控制。它的優(yōu)點(diǎn)是類(lèi)加載的速度比較快,按需加載,節(jié)省資源。
餓漢模式就是在類(lèi)加載的時(shí)候會(huì)創(chuàng)建出實(shí)例。它天生就不存在線程安全問(wèn)題。但是類(lèi)加載的速度會(huì)變慢且耗費(fèi)資源。
懶漢模式-單重檢查
示例代碼如下:
public class LazySingleton { private static LazySingleton singletoninstance = null; private Object data = new Object(); //私有化構(gòu)造方法 private LazySingleton(){ } //加鎖訪問(wèn) public static synchronized LazySingleton getInstance(){ if(singletoninstance == null){ singletoninstance = new LazySingleton(); } return singletoninstance; } public Object getData() { return data; } public void setData(Object data) { this.data = data; } }
測(cè)試代碼如下:
public class TestThread extends Thread { @Override public void run() { LazySingleton instance = LazySingleton.getInstance(); System.out.println(instance.getData()); } } public static void main(String[] args) { for(int i =0;i < 10;i++){ TestThread t = new TestThread(); t.start(); } } }
運(yùn)行結(jié)果如下:
java.lang.Object@306d3b64
java.lang.Object@306d3b64
java.lang.Object@306d3b64
java.lang.Object@306d3b64
java.lang.Object@306d3b64
java.lang.Object@306d3b64
java.lang.Object@306d3b64
java.lang.Object@306d3b64
java.lang.Object@306d3b64
java.lang.Object@306d3b64
打印出同一個(gè)object對(duì)象,表明是從同一個(gè)LazySingleton對(duì)象中獲取的數(shù)據(jù)。
但是上述代碼存在一個(gè)顯著的問(wèn)題:多個(gè)線程同時(shí)訪問(wèn)getInstance()方法都是排隊(duì)式的,即使該instance已經(jīng)被創(chuàng)建的情況下。然而,如果該instance已經(jīng)被創(chuàng)建,是可以支持并發(fā)訪問(wèn)的。需要對(duì)鎖的控制細(xì)粒度化。
懶漢模式-雙重檢查
public class LazySingleton { //聲明為volatile變量 private static volatile LazySingleton singletoninstance = null; private Object data = new Object(); private LazySingleton(){ } public static synchronized LazySingleton getInstance(){ if(singletoninstance == null){ synchronized (LazySingleton.class) { //這個(gè)第二重的的檢查是必要的 if(singletoninstance == null) singletoninstance = new LazySingleton(); } } return singletoninstance; } public Object getData() { return data; } public void setData(Object data) { this.data = data; } }
第二重檢查是為了防止:
線程A發(fā)現(xiàn)instance未被創(chuàng)建,于是申請(qǐng)鎖,進(jìn)入臨界區(qū)創(chuàng)建instance;于此同時(shí)另一個(gè)線程也發(fā)現(xiàn)instance未被創(chuàng)建,于是也要申請(qǐng)鎖去創(chuàng)建instance,問(wèn)題就這樣發(fā)生了。而且,這個(gè)instance變量要被聲明為volatile,也就是其中一個(gè)線程對(duì)它就行修改之后(也就是實(shí)例化),這一修改立馬對(duì)其他線程可見(jiàn),避免了無(wú)謂的等待。
檢查代碼同上,運(yùn)行結(jié)果同上。
餓漢模式
public class HungerSingleton { private static final HungerSingleton singletoninstance = new HungerSingleton(); private Object data = new Object(); private HungerSingleton(){ } public static HungerSingleton getInstance(){ return singletoninstance; } public Object getData() { return data; } public void setData(Object data) { this.data = data; } }
在加載該類(lèi)的時(shí)候就立馬去實(shí)例化instance,不存在線程安全問(wèn)題(由jvm保證線程安全問(wèn)題),但是存在資源浪費(fèi)、加載速度慢的問(wèn)題。
檢查代碼同上,運(yùn)行結(jié)果同上。
Holder模式
就是利用一個(gè)靜態(tài)內(nèi)部類(lèi)來(lái)實(shí)現(xiàn)instance的實(shí)例化。這里利用了靜態(tài)內(nèi)部類(lèi)的一個(gè)特性:該內(nèi)部類(lèi)的實(shí)例與外部類(lèi)的實(shí)例 沒(méi)有綁定關(guān)系,而且只有被調(diào)用到才會(huì)裝載,從而實(shí)現(xiàn)了延遲加載
public class HolderSingleton { private Object data = new Object(); private HolderSingleton(){ } private static class InnerClass{ private static HolderSingleton singletoninstance = new HolderSingleton(); } public static HolderSingleton getInstance(){ return InnerClass.singletoninstance; } public Object getData() { return data; } public void setData(Object data) { this.data = data; } }
測(cè)試代碼同上,運(yùn)行結(jié)果同上。
在加載InnerClass的時(shí)候才會(huì)去實(shí)例化這個(gè)instance,實(shí)現(xiàn)了延遲加載,并且同餓漢模式一樣,由jvm保證線程安全。這種方法值得推薦。
應(yīng)用場(chǎng)景:
在整個(gè)系統(tǒng)中,只允許共用一個(gè)實(shí)例的類(lèi)適合用單例模式來(lái)實(shí)現(xiàn),比如:
網(wǎng)站的計(jì)數(shù)器,只允許存在一個(gè)計(jì)數(shù)器實(shí)例;
線程池,只允許存在一個(gè)線程池對(duì)象;
連接池,只允許存在一個(gè)連接池對(duì)象;
知識(shí)點(diǎn)擴(kuò)充:
1.為什么要使用單例模式?
在我們?nèi)粘5墓ぷ髦校芏鄬?duì)象通常占用非常重要的系統(tǒng)資源,比如:IO處理,數(shù)據(jù)庫(kù)操作等,那我們必須要限制這些對(duì)象只有且始終使用一個(gè)公用的實(shí)例,即單例。
2.單例模式的實(shí)現(xiàn)方式
構(gòu)造函數(shù)私有化,防止其他類(lèi)生成唯一公用實(shí)例外的實(shí)例。且單例類(lèi)應(yīng)該被定義為final,也就是說(shuō)單例類(lèi)不能被繼承,因?yàn)槿绻试S繼承那子類(lèi)就都可以創(chuàng)建實(shí)例,違背了類(lèi)唯一實(shí)例的初衷。
類(lèi)中一個(gè)靜態(tài)變量來(lái)保存單實(shí)例的引用。
一個(gè)共有的靜態(tài)方法來(lái)獲取單實(shí)例的引用。
3.單例模式的UML類(lèi)圖
4.單例模式的經(jīng)典實(shí)現(xiàn)方式
餓漢式:一開(kāi)始就創(chuàng)建好實(shí)例,每次調(diào)用直接返回,經(jīng)典的“拿空間換時(shí)間”。
懶漢式:延遲加載,第一次調(diào)用的時(shí)候才加載,然后返回,以后的每次的調(diào)用就直接返回。經(jīng)典“拿時(shí)間換空間”,多線程環(huán)境下要注意解決線程安全的問(wèn)題。
登記式:對(duì)一組單例模式進(jìn)行的維護(hù),主要是在數(shù)量上的擴(kuò)展,通過(guò)線程安全的map把單例存進(jìn)去,這樣在調(diào)用時(shí),先判斷該單例是否已經(jīng)創(chuàng)建,是的話直接返回,不是的話創(chuàng)建一個(gè)登記到map中,再返回。
以上是“Java中單例模式的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)網(wǎng)站建設(shè)公司行業(yè)資訊頻道!
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)建站www.cdcxhl.com,海內(nèi)外云服務(wù)器15元起步,三天無(wú)理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性?xún)r(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專(zhuān)為企業(yè)上云打造定制,能夠滿(mǎn)足用戶(hù)豐富、多元化的應(yīng)用場(chǎng)景需求。