1. 程式人生 > >高併發下最全執行緒安全的單例模式幾種實現

高併發下最全執行緒安全的單例模式幾種實現

為了節約系統資源,有時需要確保系統中某個類只有唯一一個例項,當這個唯一例項建立成功之後,我們無法再建立一個同類型的其他物件,所有的操作都只能基於這個唯一例項。 但是餓漢式單例類不能實現延遲載入,不管將來用不用始終佔據記憶體;懶漢式單例類執行緒安全控制煩瑣,而且效能受影響。可見,無論是餓漢式單例還是懶漢式單例都存在這樣那樣的問題,相比較內部靜態(static)內部類實現可以兼併以上問題。單例模式優缺點如下:

1.主要優點

       單例模式的主要優點如下:

       (1) 單例模式提供了對唯一例項的受控訪問。因為單例類封裝了它的唯一例項,所以它可以嚴格控制客戶怎樣以及何時訪問它。

       (2)

由於在系統記憶體中只存在一個物件,因此可以節約系統資源,對於一些需要頻繁建立和銷燬的物件單例模式無疑可以提高系統的效能。

       (3) 允許可變數目的例項。基於單例模式我們可以進行擴充套件,使用與單例控制相似的方法來獲得指定個數的物件例項,既節省系統資源,又解決了單例單例物件共享過多有損效能的問題。

2.主要缺點

       單例模式的主要缺點如下:

       (1) 由於單例模式中沒有抽象層,因此單例類的擴充套件有很大的困難。

       (2) 單例類的職責過重,在一定程度上違背了“單一職責原則”。因為單例類既充當了工廠角色,提供了工廠方法,同時又充當了產品角色,包含一些業務方法,將產品的建立和產品的本身的功能融合到一起。

       (3) 現在很多面向物件語言(JavaC#)的執行環境都提供了自動垃圾回收的技術,因此,如果例項化的共享物件長時間不被利用,系統會認為它是垃圾,會自動銷燬並回收資源,下次利用時又將重新例項化,這將導致共享的單例物件狀態的丟失。


1 什麼是單例模式?

在文章開始之前我們還是有必要介紹一下什麼是單例模式。單例模式是為確保一個類只有一個例項,併為整個系統提供一個全域性訪問點的一種模式方法。

從概念中體現出了單例的一些特點:

(1)、在任何情況下,單例類永遠只有一個例項存在

(2)、單例需要有能力為整個系統提供這一唯一例項 

為了便於讀者更好的理解這些概念,下面給出這麼一段內容敘述:

在計算機系統中,執行緒池、快取、日誌物件、對話方塊、印表機、顯示卡的驅動程式物件常被設計成單例。這些應用都或多或少具有資源管理器的功能。每臺計算機可以有若干個印表機,但只能有一個Printer Spooler,以避免兩個列印作業同時輸出到印表機中。每臺計算機可以有若干通訊埠,系統應當集中管理這些通訊埠,以避免一個通訊埠同時被兩個請求同時呼叫。總之,選擇單例模式就是為了避免不一致狀態,避免政出多頭。

正是由於這個特點,單例物件通常作為程式中的存放配置資訊的載體,因為它能保證其他物件讀到一致的資訊。例如在某個伺服器程式中,該伺服器的配置資訊可能存放在資料庫或檔案中,這些配置資料由某個單例物件統一讀取,服務程序中的其他物件如果要獲取這些配置資訊,只需訪問該單例物件即可。這種方式極大地簡化了在複雜環境 下,尤其是多執行緒環境下的配置管理,但是隨著應用場景的不同,也可能帶來一些同步問題。
    

2 各式各樣的單例實現

溫馨提示:本文敘述中涉及到的相關原始碼可以在這裡進行下載原始碼,讀者可免積分下載。

1、餓漢式單例

餓漢式單例是指在方法呼叫前,例項就已經建立好了。下面是實現程式碼:

  1. package org.mlinge.s01;  
  2. publicclass MySingleton {  
  3.     privatestatic MySingleton instance = new MySingleton();  
  4.     private MySingleton(){}  
  5.     publicstatic MySingleton getInstance() {  
  6.         return instance;  
  7.     }  
  8. }  
以上是單例的餓漢式實現,我們來看看餓漢式在多執行緒下的執行情況,給出一段多執行緒的執行程式碼:
  1. package org.mlinge.s01;  
  2. publicclass MyThread extends Thread{  
  3.     @Override
  4.     publicvoid run() {   
  5.         System.out.println(MySingleton.getInstance().hashCode());  
  6.     }  
  7.     publicstaticvoid main(String[] args) {   
  8.         MyThread[] mts = new MyThread[10];  
  9.         for(int i = 0 ; i < mts.length ; i++){  
  10.             mts[i] = new MyThread();  
  11.         }  
  12.         for (int j = 0; j < mts.length; j++) {  
  13.             mts[j].start();  
  14.         }  
  15.     }  
  16. }  

以上程式碼執行結果:

  1. 1718900954  
  2. 1718900954  
  3. 1718900954  
  4. 1718900954  
  5. 1718900954  
  6. 1718900954  
  7. 1718900954  
  8. 1718900954  
  9. 1718900954  
  10. 1718900954  

從執行結果可以看出例項變數額hashCode值一致,這說明物件是同一個,餓漢式單例實現了。

2、懶漢式單例

懶漢式單例是指在方法呼叫獲取例項時才建立例項,因為相對餓漢式顯得“不急迫”,所以被叫做“懶漢模式”。下面是實現程式碼:

  1. package org.mlinge.s02;  
  2. publicclass MySingleton {  
  3.     privatestatic MySingleton instance = null;  
  4.     private MySingleton(){}  
  5.     publicstatic MySingleton getInstance() {  
  6.         if(instance == null){//懶漢式
  7.             instance = new MySingleton();  
  8.         }  
  9.         return instance;  
  10.     }  
  11. }  
這裡實現了懶漢式的單例,但是熟悉多執行緒併發程式設計的朋友應該可以看出,在多執行緒併發下這樣的實現是無法保證例項例項唯一的,甚至可以說這樣的失效是完全錯誤的,下面我們就來看一下多執行緒併發下的執行情況,這裡為了看到效果,我們對上面的程式碼做一小點修改:
  1. package org.mlinge.s02;  
  2. publicclass MySingleton {  
  3.     privatestatic MySingleton instance = null;  
  4.     private MySingleton(){}  
  5.     publicstatic MySingleton getInstance() {  
  6.         try {   
  7.             if(instance != null){//懶漢式 
  8.             }else{  
  9.                 //建立例項之前可能會有一些準備性的耗時工作 
  10.                 Thread.sleep(300);  
  11.                 instance = new MySingleton();  
  12.             }  
  13.         } catch (InterruptedException e) {   
  14.             e.printStackTrace();  
  15.         }  
  16.         return instance;  
  17.     }  
  18. }  
這裡假設在建立例項前有一些準備性的耗時工作要處理,多執行緒呼叫:
  1. package org.mlinge.s02;  
  2. publicclass MyThread extends Thread{  
  3.     @Override
  4.     publicvoid run() {   
  5.         System.out.println(MySingleton.getInstance().hashCode());  
  6.     }  
  7.     publicstaticvoid main(String[] args) {   
  8.         MyThread[] mts = new MyThread[10];  
  9.         for(int i = 0 ; i < mts.length ; i++){  
  10.             mts[i] = new MyThread();  
  11.         }  
  12.         for (int j = 0; j < mts.length; j++) {  
  13.             mts[j].start();  
  14.         }  
  15.     }  
  16. }  

執行結果如下:

  1. 1210420568  
  2. 1210420568  
  3. 1935123450  
  4. 1718900954  
  5. 1481297610  
  6. 1863264879  
  7. 369539795  
  8. 1210420568  
  9. 1210420568  
  10. 602269801  

從這裡執行結果可以看出,單例的執行緒安全性並沒有得到保證,那要怎麼解決呢?

3、執行緒安全的懶漢式單例

要保證執行緒安全,我們就得需要使用同步鎖機制,下面就來看看我們如何一步步的解決 存線上程安全問題的懶漢式單例(錯誤的單例)。

(1)、 方法中宣告synchronized關鍵字

出現非執行緒安全問題,是由於多個執行緒可以同時進入getInstance()方法,那麼只需要對該方法進行synchronized的鎖同步即可:

  1. package org.mlinge.s03;  
  2. publicclass MySingleton {  
  3.     privatestatic MySingleton instance = null;  
  4.     private MySingleton(){}  
  5.     publicsynchronizedstatic MySingleton getInstance() {  
  6.         try {   
  7.             if(instance != null){//懶漢式 
  8.             }else{  
  9.                 //建立例項之前可能會有一些準備性的耗時工作 
  10.                 Thread.sleep(300);  
  11.                 instance = new MySingleton();  
  12.             }  
  13.         } catch (InterruptedException e) {   
  14.             e.printStackTrace();  
  15.         }  
  16.         return instance;  
  17.     }  
  18. }  

此時任然使用前面驗證多執行緒下執行情況的MyThread類來進行驗證,將其放入到org.mlinge.s03包下執行,執行結果如下:

  1. 1689058373  
  2. 1689058373  
  3. 1689058373  
  4. 1689058373  
  5. 1689058373  
  6. 1689058373  
  7. 1689058373  
  8. 1689058373  
  9. 1689058373  
  10. 1689058373  

從執行結果上來看,問題已經解決了,但是這種實現方式的執行效率會很低。同步方法效率低,那我們考慮使用同步程式碼塊來實現:

(2)、 同步程式碼塊實現

  1. package org.mlinge.s03;  
  2. publicclass MySingleton {  
  3.     privatestatic MySingleton instance = null;  
  4.     private MySingleton(){}  
  5.     //public synchronized static MySingleton getInstance() {
  6.     publicstatic MySingleton getInstance() {  
  7.         try {   
  8.             synchronized (MySingleton.class) {  
  9.                 if(instance != null){//懶漢式 
  10.                 }else{  
  11.                     //建立例項之前可能會有一些準備性的耗時工作 
  12.                     Thread.sleep(300);  
  13.                     instance = new MySingleton();  
  14.                 }  
  15.             }  
  16.         } catch (InterruptedException e) {   
  17.             e.printStackTrace();  
  18.         }  
  19.         return instance;  
  20.     }  
  21. }  
這裡的實現能夠保證多執行緒併發下的執行緒安全性,但是這樣的實現將全部的程式碼都被鎖上了,同樣的效率很低下。

(3)、 針對某些重要的程式碼來進行單獨的同步(可能非執行緒安全)

針對某些重要的程式碼進行單獨的同步,而不是全部進行同步,可以極大的提高執行效率,我們來看一下:

  1. package org.mlinge.s04;  
  2. publicclass MySingleton {  
  3.     privatestatic MySingleton instance = null;  
  4.     private MySingleton(){}  
  5.     publicstatic MySingleton getInstance() {  
  6.         try {    
  7.             if(instance != null){//懶漢式 
  8.             }else{  
  9.                 //建立例項之前可能會有一些準備性的耗時工作 
  10.                 Thread.sleep(300);  
  11.                 synchronized (MySingleton.class) {  
  12.                     instance = new MySingleton();  
  13.                 }  
  14.             }   
  15.         } catch (InterruptedException e) {   
  16.             e.printStackTrace();  
  17.         }  
  18.         return instance;  
  19.     }  
  20. }  
此時同樣使用前面驗證多執行緒下執行情況的MyThread類來進行驗證,將其放入到org.mlinge.s04包下執行,執行結果如下:
  1. 1481297610  
  2. 397630378  
  3. 1863264879  
  4. 1210420568  
  5. 1935123450  
  6. 369539795  
  7. 590202901  
  8. 1718900954  
  9. 1689058373  
  10. 602269801  
從執行結果來看,這樣的方法進行程式碼塊同步,程式碼的執行效率是能夠得到提升,但是卻沒能保住執行緒的安全性。看來還得進一步考慮如何解決此問題。

(4)、 Double Check Locking 雙檢查鎖機制(推薦)

為了達到執行緒安全,又能提高程式碼執行效率,我們這裡可以採用DCL的雙檢查鎖機制來完成,程式碼實現如下:

  1. package org.mlinge.s05;  
  2. publicclass MySingleton {  
  3.     //使用volatile關鍵字保其可見性
  4.     volatileprivatestatic MySingleton instance = null;  
  5.     private MySingleton(){}  
  6.     publicstatic MySingleton getInstance() {  
  7.         try {    
  8.             if(instance != null){//懶漢式 
  9.             }else{  
  10.                 //建立例項之前可能會有一些準備性的耗時工作 
  11.                 Thread.sleep(300);  
  12.                 synchronized (MySingleton.class) {  
  13.                     if(instance == null){//二次檢查
  14.                         instance = new MySingleton();  
  15.                     }  
  16.                 }  
  17.             }   
  18.         } catch (InterruptedException e) {   
  19.             e.printStackTrace();  
  20.         }  
  21.         return instance;  
  22.     }  
  23. }  
將前面驗證多執行緒下執行情況的MyThread類放入到org.mlinge.s05包下執行,執行結果如下:
  1. 369539795
  2. 369539795
  3. 369539795
  4. 369539795
  5. 369539795
  6. 369539795
  7. 369539795
  8. 369539795
  9. 369539795
  10. 369539795
從執行結果來看,該中方法保證了多執行緒併發下的執行緒安全性。

這裡在宣告變數時使用了volatile關鍵字來保證其執行緒間的可見性;在同步程式碼塊中使用二次檢查,以保證其不被重複例項化。集合其二者,這種實現方式既保證了其高效性,也保證了其執行緒安全性。

4、使用靜態內建類實現單例模式

DCL解決了多執行緒併發下的執行緒安全問題,其實使用其他方式也可以達到同樣的效果,程式碼實現如下:

  1. package org.mlinge.s06;  
  2. publicclass MySingleton {  
  3.     //內部類
  4.     privatestaticclass MySingletonHandler{  
  5.         privatestatic MySingleton instance = new MySingleton();  
  6.     }   
  7.     private MySingleton(){}  
  8.     publicstatic MySingleton getInstance() {   
  9.         return MySingletonHandler.instance;  
  10.     }  
  11. }  
以上程式碼就是使用靜態內建類實現了單例模式,這裡將前面驗證多執行緒下執行情況的MyThread類放入到org.mlinge.s06包下執行,執行結果如下:
  1. 1718900954
  2. 1718900954
  3. 1718900954
  4. 1718900954
  5. 1718900954
  6. 1718900954
  7. 1718900954
  8. 1718900954
  9. 1718900954
  10. 1718900954
從執行結果來看,靜態內部類實現的單例在多執行緒併發下單個例項得到了保證。

5、序列化與反序列化的單例模式實現

靜態內部類雖然保證了單例在多執行緒併發下的執行緒安全性,但是在遇到序列化物件時,預設的方式執行得到的結果就是多例的。

程式碼實現如下:

  1. package org.mlinge.s07;  
  2. import java.io.Serializable;  
  3. publicclass MySingleton implements Serializable {  
  4.     privatestaticfinallong serialVersionUID = 1L;  
  5.     //內部類
  6.     privatestaticclass MySingletonHandler{  
  7.         privatestatic MySingleton instance = new MySingleton();  
  8.     }   
  9.     private MySingleton(){}  
  10.     publicstatic MySingleton getInstance() {   
  11.         return MySingletonHandler.instance;  
  12.     }  
  13. }  
序列化與反序列化測試程式碼:
  1. package org.mlinge.s07;  
  2. import java.io.File;  
  3. import java.io.FileInputStream;  
  4. import java.io.FileNotFoundException;  
  5. import java.io.FileOutputStream;  
  6. import java.io.IOException;  
  7. import java.io.ObjectInputStream;  
  8. import java.io.ObjectOutputStream;  
  9. publicclass SaveAndReadForSingleton {  
  10.     publicstaticvoid main(String[] args) {  
  11.         MySingleton singleton = MySingleton.getInstance();  
  12.         File file = new File("MySingleton.txt");  
  13.         try {  
  14.             FileOutputStream fos = new FileOutputStream(file);  
  15.             ObjectOutputStream oos = new ObjectOutputStream(fos);  
  16.             oos.writeObject(singleton);  
  17.             fos.close();  
  18.             oos.close();  
  19.             System.out.println(singleton.hashCode());  
  20.         } catch (FileNotFoundException e) {   
  21.             e.printStackTrace();  
  22.         } catch (IOException e) {   
  23.             e.printStackTrace();  
  24.         }  
  25.         try {  
  26.             FileInputStream fis = new FileInputStream(file);  
  27.             ObjectInputStream ois = new ObjectInputStream(fis);  
  28.             MySingleton rSingleton = (MySingleton) ois.readObject();  
  29.             fis.close();  
  30.             ois.close();  
  31.             System.out.println(rSingleton.hashCode());  
  32.         } catch (FileNotFoundException e) {   
  33.             e.printStackTrace();  
  34.         } catch (IOException e) {   
  35.             e.printStackTrace();  
  36.         } catch (ClassNotFoundException e) {   
  37.             e.printStackTrace();  
  38.         }  
  39.     }  
  40. }  
執行以上程式碼,得到的結果如下:
  1. 865113938  
  2. 1442407170  
從結果中我們發現,序列號物件的hashCode和反序列化後得到的物件的hashCode值不一樣,說明反序列化後返回的物件是重新例項化的,單例被破壞了。那怎麼來解決這一問題呢?

解決辦法就是在反序列化的過程中使用readResolve()方法,單例實現的程式碼如下:

  1. package org.mlinge.s07;  
  2. import java.io.ObjectStreamException;  
  3. import java.io.Serializable;  
  4. publicclass MySingleton implements Serializable {  
  5.     privatestaticfinallong serialVersionUID = 1L;  
  6.     //內部類
  7.     privatestaticclass MySingletonHandler{  
  8.         privatestatic MySingleton instance = new MySingleton();  
  9.     }   
  10.     private MySingleton(){}  
  11.     publicstatic MySingleton getInstance() {   
  12.         return MySingletonHandler.instance;  
  13.     }  
  14.     //該方法在反序列化時會被呼叫,該方法不是介面定義的方法,有點兒約定俗成的感覺
  15.     protected Object readResolve() throws ObjectStreamException {  
  16.         System.out.println("呼叫了readResolve方法!");  
  17.         return MySingletonHandler.instance;   
  18.     }  
  19. }  
再次執行上面的測試程式碼,得到的結果如下:
  1. 865113938  
  2. 呼叫了readResolve方法!  
  3. 865113938  
從執行結果可知,新增readResolve方法後反序列化後得到的例項和序列化前的是同一個例項,單個例項得到了保證。

6、使用static程式碼塊實現單例

靜態程式碼塊中的程式碼在使用類的時候就已經執行了,所以可以應用靜態程式碼塊的這個特性的實現單例設計模式。

  1. package org.mlinge.s08;  
  2. publicclass MySingleton{  
  3.     privatestatic MySingleton instance = null;  
  4.     private MySingleton(){}  
  5.     static{  
  6.         instance = new MySingleton();  
  7.     }  
  8.     publicstatic MySingleton getInstance() {   
  9.         return instance;  
  10.     }   
  11. }  
測試程式碼如下:
  1. package org.mlinge.s08;  
  2. publicclass MyThread extends Thread{  
  3.     @Override
  4.     publicvoid run() {   
  5.         for (int i = 0; i < 5; i++) {  
  6.             System.out.println(MySingleton.getInstance().hashCode());  
  7.         }  
  8.     }  
  9.     publicstaticvoid main(String[] args) {   
  10.         MyThread[] mts = new MyThread[3];  
  11.         for(int i = 0 ; i < mts.length ; i++){  
  12.             mts[i] = new MyThread();  
  13.         }  
  14.         for (int j = 0; j < mts.length; j++) {  
  15.             mts[j].start();  
  16.         }  
  17.     }  
  18. }  
執行結果如下:
  1. 1718900954
  2. 1718900954
  3. 1718900954
  4. 1718900954
  5. 1718900954
  6. 1718900954
  7. 1718900954
  8. 1718900954
  9. 1718900954
  10. 1718900954
  11. 1718900954
  12. 1718900954
  13. 1718900954
  14. 1718900954
  15. 1718900954
從執行結果看,單例的執行緒安全性得到了保證。

7、使用列舉資料型別實現單例模式

列舉enum和靜態程式碼塊的特性相似,在使用列舉時,構造方法會被自動呼叫,利用這一特性也可以實現單例:

  1. package org.mlinge.s09;  
  2. publicenum EnumFactory{   
  3.     singletonFactory;  
  4.     private MySingleton instance;  
  5.     private EnumFactory(){//列舉類的構造方法在類載入是被例項化
  6.         instance = new MySingleton();  
  7.     }  
  8.     public MySingleton getInstance(){  
  9.         return instance;  
  10.     }  
  11. }  
  12. class MySingleton{//需要獲實現單例的類,比如資料庫連線Connection
  13.     public MySingleton(){}   
  14. }  
測試程式碼如下:
  1. package org.mlinge.s09;  
  2. publicclass MyThread extends Thread{  
  3.     @Override
  4.     publicvoid run() {   
  5. 相關推薦

    併發執行安全模式實現

    為了節約系統資源,有時需要確保系統中某個類只有唯一一個例項,當這個唯一例項建立成功之後,我們無法再建立一個同類型的其他物件,所有的操作都只能基於這個唯一例項。 但是餓漢式單例類不能實現延遲載入,不管將來用不用始終佔據記憶體;懶漢式單例類執行緒安全控制煩瑣,而且效能受影響。可

    [C++][執行安全]模式雙檢查鎖和執行

    問題 在設計模式中,有一個很經典的模式-單例模式,它可能是實現上最簡單的模式,在程式碼中也經常使用,在單執行緒下,毫無疑問延遲化載入是比較常用的,但是在多執行緒條件下,單例模式的延遲載入可能就會出現一些問題。 如以下的程式碼: T* GetInstance(

    C++的模式執行安全模式(懶漢/餓漢)

    單例模式 單例模式:是一種常用的軟體設計模式。在它的核心結構中只包含一個被稱為單例的特殊類。通過單例模式可以保證系統中一個類只有一個例項。即一個類只有一個物件例項。   實現簡單的單例模式:建構函式宣告為private或protect防止被外部函式

    併發第三彈:執行安全-原子性

    執行緒安全性? 執行緒安全性主要體現在三個方面:原子性、可見性、有序性 原子性:提供了互斥訪問,同一時刻只能有一個執行緒來對它進行操作 可見性:一個執行緒對主記憶體的修改可以及時的被其他執行緒觀察到 有序性:一個執行緒觀察其他執行緒中的指令執行順序,由於指令重排序的存在,該觀察結果一般雜亂無序。 本章主

    Java併發程式設計(3)-構造執行安全類的模式

    文章目錄 一、例項限制模式 1.1、 限制變數確保執行緒安全 1.2、分析ArrayList的執行緒安全性 1.3、總結 二、委託執行緒安全模式 2.

    執行安全設計模式+序列化

    懶漢式單例模式會引來執行緒安全問題,即多執行緒時可能會建立多個例項,而且在反序列化時也可能會建立新的例項。看了大大們的實現方式,覺得以下一種比較簡單方便理解。 一、下面是會造成執行緒安全的餓漢單例模式。用四列印下會發現hashcode不一致 public class Singleton {

    高效能的執行安全——Java基礎語法系列

    大家都知道,一般實現單例有兩種寫法: 餓漢式 和 懶漢式, 餓漢式是執行緒安全的,在編譯期間已完成初始化,載入到了記憶體裡。 懶漢式一般寫法是非執行緒安全的, 那懶漢式的執行緒安全單例應該如何實現呢,以及如何寫出低耗能的執行緒安全單例呢 ? 單例實現關鍵點 建構函式私有,

    Qt實現支援多執行模式

    1. 程式碼介紹 實現單例模式的程式碼很多。 本文的單例模式實現程式碼是本人一直在工程專案中使用的,現拿出和大家交流分享。 本文實現的單例模式,支援多執行緒,採用雙重校驗檢索的方式,整合析構類,杜絕記憶體洩漏,穩定性好。 使用C++/Qt的朋友們可以瞭解一下。 不再廢話,直接上程式碼。

    java通過雙重檢測或列舉類實現執行安全(懶漢模式)

    雙重檢測實現 /** * 懶漢模式->雙重同步鎖單例模式 */ public class SingletonExample5 { private SingletonExample5() { } //volatile + 雙重檢測機制 -> 禁止指令重排序

    執行安全(與多)

          又週五了,時間過得好快,住在集體宿舍,幾個宅男共處一室好是無聊,習慣性來到CSDN。今天一個應屆生同事突然問我為什麼老大要求我們不要在Service裡寫成員變數,說不安全,說為什麼不安全讓他自己去了解,看上去他沒有找到頭緒很是痛苦,想想當初這個問題也困擾過自己,向

    執行安全的生產者消費者四實現方法

    問題描述 在IT技術面試過程中,我們經常會遇到生產者消費者問題(Producer-consumer problem), 這是多執行緒併發協作問題的經典案例。場景中包含三個物件,生產者(Producer),消費者(Consumer)以及一個固定大小的緩衝區(Buffer)。生產者的主要作用是不斷生成資料放到緩衝

    執行涉及模式

    /** * 單例模式涉及的兩個問題 * * @author 羅摩銜那 * */ /* * 惡漢式 * 優點:當類被載入的時候,已經建立好了一個靜態的物件,因此,是執行緒安全的 * 缺點:這個物件還沒有被使用就被創建出來了 */ class Single { private s

    日常小結-多執行模式的三實現方式

    多執行緒單例模式在很多併發的書裡面都有寫。這裡做一個簡單的總結。主要內容來自《java併發程式設計的藝術》《java多執行緒程式設計核心》 單例模式的分類 餓漢模式:類初始化的時候就進行建立單例模式 懶漢模式:在呼叫getinstance方法的時候才建

    JAVA_多執行_模式

    這篇是入職之後的第二篇了,上一篇我簡單介紹了一下LOCK裡面的類的方法,感興趣的話可以去了解一下,以後堅持每週至少會更新一篇關於多執行緒方面的文章,希望博友們可以一起加油成長。 這篇主要的內容是單例模式在多執行緒環境下的設計,這篇算是比較重要的內容,我會進行文字和程式碼的共同說明來講解記錄 1、立即載入(餓

    【Java多執行模式與多執行

    單例模式大家都不陌生,即讓一個類只有一個例項。 單例模式分為懶漢式和餓漢式。 懶漢式☞方法呼叫時再例項化物件,什麼時候用什麼時候例項化,比較懶。 餓漢式☞方法呼叫前物件就已經建立好了,比較有捉急。 本文著重描述懶漢式與多執行緒的內容。 1.餓漢式 public

    Java多執行模式-yellowcong

    我們常見的單利模式有餓漢式和懶漢式,懶漢式,就是在用的時候,再例項化物件,餓漢式,是還沒有開飯,就已經把物件例項化好了。在多執行緒開發中,解決單例的時候,有兩種解決方案,1、(懶漢式)同步程式碼塊

    馬士兵老師併發之6大執行

    Executor 執行器,這是一個介面,內部維護了一個方法execute它負責執行一項任務。引數為Runnable,方法的具體實現由我們自己來執行。如下面的程式碼,我們既可以使用單純的方法呼叫也可以新啟一個新的執行緒去執行Runnable的run方法。 import ja

    併發第六彈:執行封閉

    當訪問共享的可變資料時,通常需要使用同步。一種避免使用同步的方式就是不共享資料。如果僅在單執行緒內訪問資料,就不需要同步。這種技術被稱為執行緒封閉。 它其實就是把物件封裝到一個執行緒裡,只有一個執行緒能看到這個物件,那麼這個物件就算不是執行緒安全的,也不會出現任何執行緒安全方面的問題。 二 執行緒封閉技術有

    java併發學習(九)-----多執行的團隊協作:同步控制

    Java高併發學習(八)-------多執行緒的團隊協作:同步控制   同步控制是併發程式必不可少的重要手段。之前介紹的synchronized關鍵字就是一種最簡單的控制方法。同時,wait()和notify()方法起到了執行緒等待和通知的作用。這些工具對於實現複雜的多

    java併發之如何解決執行安全問題

    併發(concurrency)一個並不陌生的詞,簡單來說,就是cpu在同一時刻執行多個任務。 而Java併發則由多執行緒實現的。 在jvm的世界裡,執行緒就像不相干的平行空間,序列在虛擬機器中。(當然這是比較籠統的說法,執行緒之間是可以互動的,他們也不一定是序列。) 多執行緒的存在就是壓榨cpu,提高程