溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Java多線程實(shí)戰(zhàn)之單例模式與多線程的實(shí)例詳解

發(fā)布時(shí)間:2020-09-16 17:02:53 來源:腳本之家 閱讀:112 作者:邋遢的流浪劍客 欄目:編程語言

1、立即加載/餓漢模式

// 立即加載/餓漢模式
public class MyObject {
 private static final MyObject myObject = new MyObject();
 private MyObject() {
 }
 public static MyObject getInstance() {
 return myObject;
 }
}

立即加載/餓漢模式是在類創(chuàng)建的同時(shí)已經(jīng)創(chuàng)建好一個(gè)靜態(tài)的對(duì)象供系統(tǒng)使用,不存在線程安全問題

2、延遲加載/懶漢模式

// 延遲加載/懶漢模式
public class MyObject {
 private static MyObject myObject;
 private MyObject() {
 }
 public static MyObject getInstance() {
 if (myObject == null) {
  myObject = new MyObject();
 }
 return myObject;
 }
}

延遲加載/懶漢模式是在調(diào)用方法時(shí)實(shí)例才被創(chuàng)建,在多線程環(huán)境下,會(huì)出現(xiàn)取出多個(gè)實(shí)例的情況,與單例模式的初衷是相背離的

1)、延遲加載/懶漢模式在多線程環(huán)境下創(chuàng)建出多個(gè)實(shí)例:

// 延遲加載/懶漢模式
public class MyObject {
 private static MyObject myObject;
 private MyObject() {
 }
 public static MyObject getInstance() {
 try {
  if (myObject == null) {
  TimeUnit.SECONDS.sleep(3);
  myObject = new MyObject();
  }
 } catch (InterruptedException e) {
  e.printStackTrace();
 }
 return myObject;
 }
}
public class MyThread extends Thread {
 @Override
 public void run() {
 System.out.println(MyObject.getInstance().hashCode());
 }
}
public class Run {
 public static void main(String[] args) {
 MyThread myThread = new MyThread();
 MyThread myThread2 = new MyThread();
 MyThread myThread3 = new MyThread();
 myThread.start();
 myThread2.start();
 myThread3.start();
 }
}

運(yùn)行結(jié)果:三次打印的hashCode不完全相等

2)、通過聲明synchronized關(guān)鍵字解決線程安全問題:

// 延遲加載/懶漢模式
public class MyObject {
 private static MyObject myObject;
 private MyObject() {
 }
 public static synchronized MyObject getInstance() {
 try {
  if (myObject == null) {
  TimeUnit.SECONDS.sleep(3);
  myObject = new MyObject();
  }
 } catch (InterruptedException e) {
  e.printStackTrace();
 }
 return myObject;
 }
}

使用synchronized關(guān)鍵字,這種方法的運(yùn)行效率很低,是同步運(yùn)行的,下一個(gè)線程想要取得對(duì)象,則必須等上一個(gè)線程釋放鎖之后,才可以繼續(xù)執(zhí)行

3)、使用同步代碼塊解決線程安全問題:

// 延遲加載/懶漢模式
public class MyObject {
 private static MyObject myObject;
 private MyObject() {
 }
 public static MyObject getInstance() {
 try {
  // 相當(dāng)于public static synchronized MyObject getInstance()
  synchronized (MyObject.class) {
  if (myObject == null) {
   TimeUnit.SECONDS.sleep(3);
   myObject = new MyObject();
  }
  }
 } catch (InterruptedException e) {
  e.printStackTrace();
 }
 return myObject;
 }
}

加入同步代碼塊,這種方法的運(yùn)行效率也是非常低,和synchronized同步方法一樣是同步運(yùn)行的

4)、針對(duì)某些重要的代碼進(jìn)行單獨(dú)的同步

// 延遲加載/懶漢模式
public class MyObject {
 private static MyObject myObject;
 private MyObject() {
 }
 public static MyObject getInstance() {
 try {
  if (myObject == null) {
  TimeUnit.SECONDS.sleep(3);
  synchronized (MyObject.class) {
   myObject = new MyObject();
  }
  }
 } catch (InterruptedException e) {
  e.printStackTrace();
 }
 return myObject;
 }
}

此方法只對(duì)實(shí)例化對(duì)象的關(guān)鍵代碼進(jìn)行同步,從語句的結(jié)構(gòu)上來講,運(yùn)行的效率的確得到了提升。但如果是多線程的情況下還是無法解決得到同一個(gè)實(shí)例對(duì)象的結(jié)果

5)、使用DCL雙檢查鎖機(jī)制

// 延遲加載/懶漢模式
public class MyObject {
 private volatile static MyObject myObject;
 private MyObject() {
 }
 public static MyObject getInstance() {
 try {
  if (myObject == null) {
  TimeUnit.SECONDS.sleep(3);
  synchronized (MyObject.class) {
   if (myObject == null) {
   myObject = new MyObject();
   }
  }
  }
 } catch (InterruptedException e) {
  e.printStackTrace();
 }
 return myObject;
 }
}

使用DCL雙檢查鎖機(jī)制,既保證了不需要同步代碼的異步執(zhí)行性,又保證了單例的效果

3、使用靜態(tài)內(nèi)部類實(shí)現(xiàn)單例模式

public class MyObject {
 private static class MyObjectHandler {
 private static MyObject myObject = new MyObject();
 }
 private MyObject() {
 }
 public static MyObject getInstance() {
 return MyObjectHandler.myObject;
 }
}

4、使用靜態(tài)代碼塊實(shí)現(xiàn)單例模式

public class MyObject {
 private static MyObject instance = null;
 private MyObject() {
 }
 static {
 instance = new MyObject();
 }
 public static MyObject getInstance() {
 return instance;
 }
}

5、使用enum枚舉實(shí)現(xiàn)單例模式

public class MyObject {
 public enum MyEnumSingleton {
 objectFactory;
 private MyObject myObject;
 private MyEnumSingleton() {
  myObject = new MyObject();
 }
 public MyObject getInstance() {
  return myObject;
 }
 }
 public static MyObject getInstance() {
 return MyEnumSingleton.objectFactory.getInstance();
 }
}

枚舉enum和靜態(tài)代碼塊的特性相似,在使用枚舉類時(shí),構(gòu)造方法會(huì)被自動(dòng)調(diào)用,使用這個(gè)特性實(shí)現(xiàn)單例設(shè)計(jì)模式

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)億速云的支持。如果你想了解更多相關(guān)內(nèi)容請(qǐng)查看下面相關(guān)鏈接

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI