博客專欄

EEPW首頁(yè) > 博客 > 扣丁學(xué)堂Java培訓(xùn)之單例設(shè)計(jì)模式的線程同步

扣丁學(xué)堂Java培訓(xùn)之單例設(shè)計(jì)模式的線程同步

發(fā)布人:扣丁客1 時(shí)間:2020-12-24 來(lái)源:工程師 發(fā)布文章

單例模式是最常用的設(shè)計(jì)模式之一,目的是保證一個(gè)類只有一個(gè)實(shí)例。

在項(xiàng)目中的作用:


1、解決因?yàn)轭l繁創(chuàng)建對(duì)象,導(dǎo)致資源消耗過(guò)大的問(wèn)題,如:數(shù)據(jù)庫(kù)的連接池,連接池用于創(chuàng)建數(shù)據(jù)庫(kù)連接,并對(duì)連接進(jìn)行回收使用,能減少數(shù)據(jù)庫(kù)連接的創(chuàng)建次數(shù),從而提高效率,但是連接池對(duì)象本身在項(xiàng)目中只需要一個(gè),就需要使用單例模式。類似的還有線程池等。

2、項(xiàng)目中能共享的工具類,如Java中的Runtime類能提供各種運(yùn)行環(huán)境系統(tǒng)參數(shù),它就被設(shè)計(jì)成了單例模式。

實(shí)現(xiàn)單例的過(guò)程:

1、要保證類只能創(chuàng)建一個(gè)對(duì)象,就必須隱藏類的構(gòu)造方法,所以要將構(gòu)造方法定義為私有的

2、在類中調(diào)用構(gòu)造方法創(chuàng)建對(duì)象,定義靜態(tài)方法用于返回對(duì)象。

下面這種單例模式屬于餓漢式單例模式,既一開(kāi)始就將對(duì)象實(shí)例化。這樣的做法會(huì)導(dǎo)致性能的降低,一般我們會(huì)采用延遲加載的方式,既需要對(duì)象時(shí)再實(shí)例化。

  classHunger{
  //靜態(tài)的實(shí)例
  privatestaticHungerhunger=newHunger();
  //隱藏構(gòu)造方法
  privateHunger(){}
  //返回靜態(tài)實(shí)例
  publicstaticHungergetInstance(){
  returnhunger;
  }
  }


下面這種是懶漢式單例模式,既開(kāi)始不實(shí)例化對(duì)象,到需要該實(shí)例時(shí)再實(shí)例化,提高了運(yùn)行效率。

  publicclassLazySingleton{
  //靜態(tài)的實(shí)例
  privatestaticLazySingletonsingle=null;
  //隱藏構(gòu)造方法
  privateLazySingleton(){
  System.out.println("創(chuàng)建LazySingleton對(duì)象");
  }
  //返回靜態(tài)實(shí)例
  publicstaticLazySingletongetInstance(){
  if(single==null){
  single=newLazySingleton();
  }
  returnsingle;
  }
  }


線程安全問(wèn)題:懶漢單例模式在單線程環(huán)境沒(méi)有問(wèn)題,但在多線程環(huán)境下就會(huì)出現(xiàn)問(wèn)題。

執(zhí)行代碼,"創(chuàng)建LazySingleton對(duì)象"這句話會(huì)輸出多次,也就是創(chuàng)建了多個(gè)對(duì)象。

  for(inti=0;i<100;i++){
  newThread(newRunnable(){
  @Override
  publicvoidrun(){
  System.out.println(LazySingleton.getInstance());
  }}).start();
  }


分析原因:

假設(shè)線程1滿足getInstance方法中single==null條件后,準(zhǔn)備執(zhí)行創(chuàng)建對(duì)象的代碼,然后CPU被其它線程搶占,其它線程在getInstance方法中創(chuàng)建對(duì)象,然后線程1搶回CPU繼續(xù)執(zhí)行剛才未完成的創(chuàng)建對(duì)象代碼,這樣就創(chuàng)建了多個(gè)對(duì)象。

線程同步問(wèn)題的解決方法:

1、使用同步方法

publicstaticsynchronizedLazySingletongetInstance(){
if(single==null){
single=newLazySingleton();
}
returnsingle;
}

執(zhí)行剛才多線程的代碼后,我們發(fā)現(xiàn)可以解決同步問(wèn)題,但是同步方法存在的問(wèn)題是每個(gè)線程進(jìn)入后都會(huì)加鎖,執(zhí)行效率低。

2、使用同步代碼塊配合if使用

publicstaticLazySingletongetInstance(){
if(single==null){
synchronized(LazySingleton.class){
single=newLazySingleton();
}
}
returnsingle;
}


同步塊和if語(yǔ)句配合使用,解決了每次都執(zhí)行上鎖導(dǎo)致的性能問(wèn)題,但是運(yùn)行代碼后我們會(huì)發(fā)現(xiàn),多線程同步的問(wèn)題還是可能出現(xiàn),原因是多個(gè)線程還是可能會(huì)同時(shí)進(jìn)入if語(yǔ)句。

3、使用雙重判斷

在同步塊中再添加一次if判斷就解決了上面的問(wèn)題,因?yàn)榫退愣鄠€(gè)線程同時(shí)進(jìn)入外層if語(yǔ)句,執(zhí)行同步塊還是要進(jìn)行一次判斷,這樣第一個(gè)線程創(chuàng)建對(duì)象后,后面的線程就不能再創(chuàng)建了。

  publicstaticLazySingletongetInstance(){
  //外層的if主要作用是判斷是否需要執(zhí)行同步塊,提高性能
  if(single==null){
  //靜態(tài)方法中將類作為鎖
  synchronized(LazySingleton.class){
  //判斷對(duì)象是否為空,為空就創(chuàng)建對(duì)象
  if(single==null){
  single=newLazySingleton();
  }
  }
  }
  returnsingle;
  }


4、靜態(tài)內(nèi)部類

這種方法結(jié)合了餓漢式和懶漢式的特點(diǎn),如果不調(diào)用getInstance方法,靜態(tài)內(nèi)部類中的創(chuàng)建對(duì)象代碼不會(huì)執(zhí)行,調(diào)用getInstance后才會(huì)執(zhí)行,也就有了懶漢式延遲加載的效果,并且由于對(duì)象是直接創(chuàng)建的,還不存在線程同步問(wèn)題。

  classMySingleton{
  privateMySingleton(){
  }
  privatestaticclassSingletonHelp{
  staticMySingletoninstance=newMySingleton();
  }
  publicstaticMySingletongetInstance(){
  returnSingletonHelp.instance;
  }
  }



總結(jié):?jiǎn)卫J降膶?shí)現(xiàn)一般有餓漢式、懶漢式和靜態(tài)內(nèi)部類等方式,餓漢式創(chuàng)建對(duì)象的性能比較低但不存在線程同步問(wèn)題,懶漢式由于是延遲加載性能更高,但存在線程同步問(wèn)題,需要使用雙重判斷解決,靜態(tài)內(nèi)部類的方式也能實(shí)現(xiàn)單例模式但是代碼可讀性稍差。

如果項(xiàng)目對(duì)性能不敏感推薦使用餓漢式,如果是單線程環(huán)境可以使用一般的懶漢式,如果需要多線程則可以使用多重判斷的懶漢式或靜態(tài)內(nèi)部類實(shí)現(xiàn)。

以上就是關(guān)于Java開(kāi)發(fā)單例設(shè)計(jì)模式線程同步的詳細(xì)介紹,最后想要了解更多可以登錄扣丁學(xué)堂官網(wǎng)咨詢??鄱W(xué)堂是專業(yè)的Java培訓(xùn)機(jī)構(gòu),不僅有專業(yè)的老師和與時(shí)俱進(jìn)的課程體系,還有大量的Java視頻教程供學(xué)員觀看學(xué)習(xí),想要學(xué)好JavaEE的小伙伴抓緊時(shí)間行動(dòng)吧。扣丁學(xué)堂java技術(shù)交流群:487098661。微信號(hào):codingbb

*博客內(nèi)容為網(wǎng)友個(gè)人發(fā)布,僅代表博主個(gè)人觀點(diǎn),如有侵權(quán)請(qǐng)聯(lián)系工作人員刪除。



關(guān)鍵詞:

相關(guān)推薦

技術(shù)專區(qū)

關(guān)閉