如何實現無鎖的執行緒安全延遲載入單例?

2022-05-07 05:27:11 字數 2295 閱讀 4926

單例是較為常見的設計模式,在實現延遲載入時,會出現執行緒安全的問題,我們一般採用加鎖的方式,不採用加顯式鎖的方式例如列舉、以及非延遲載入的方式之類的最終虛擬機器在執行的時候會幫我們加鎖。

這個其實很好理解,我們可以看下如下的**

class

sim

public

static

sim getinstance()

}public

class

test2 );

thread.setname("test");

thread.setpriority(10);

thread thread1 = new thread(()->);

thread1.setname("test111");

thread1.setpriority(1);

thread.start();

thread1.start();}}

這是乙個典型的依靠jvm保證執行緒安全的單例模式,這兒是沒有顯式的加鎖的。我們在sim的初始化方法中列印了執行緒名字,並且執行了乙個死迴圈。main方法執行後第乙個載入的執行緒jvm會讓其獲得鎖並執行構造方法,另外乙個執行緒則會等待。列印結果則會如下

發現只有test111載入了  我們檢視執行緒資訊發現

我們的test執行緒處於object.wait()阻塞狀態而不是正常的runnable狀態。  test111則是正常的執行狀態 且只有test111執行了方法,並自旋在了也就是建構函式中

那麼如何實現乙個不加鎖的單例呢?    可以借助cas來實現

先看下不安全的情況

class

single;

private

static

single getinstance()

return

single;

/********安全*******

*///

if ( sing.get() != null )

single());

//return sing.get();

}

public

static

void main(string args) throws

interruptedexception

catch

(interruptedexception e)

catch

(brokenbarrierexception e)

single instance =single.getinstance();

map.put(instance,"1");

countdownlatch.countdown();

});}

executorservice.shutdown();

countdownlatch.await();

system.out.println(string.format("共初始化 %d 個,分別為 %s",map.keyset().size(),map.keyset()));
} }
為了更加容易模擬,我在初始化中加入了稍微費時點兒的操作。並且借助cyclicbarrier 來模擬多個執行緒同一時間請求。這樣在不安全的情況下,得到的結果會可能如下有多個

然後我們把不安全的步驟注釋掉,執行安全的步驟時,多次試驗下均只有乙個

private

static

single getinstance()

//return single;

/********安全*******

*/if ( sing.get() != null

)//只有乙個執行緒會成功

sing.compareandset(

null,new

single());

return

sing.get();

}

這兒的sing.compareandset(null,new single());使用cas指令來保證多個執行緒對原子引用賦值時確保只有乙個會賦值成功。做到了不加鎖的情況下實現單例

多次執行結果如下   都只有乙個結果

當然了 本案例只是說明如何實現無鎖化的單例,但並不推薦,因為這種方式只能保證最終我們獲取到的物件都是同乙個。而類的建構函式則是可能被執行很多次的。

無鎖,執行緒安全,延遲載入的單例實現(C )

單例 singleton 是非常常見,也非常有用的設計模式,當然了,面試中也是經常會被問到的 在幾乎所有的專案中都能看到它的身影。簡而言之,單例保證了乙個自定義型別在整個程式的生命週期只被建立一次。要實現乙個簡單的單例是也很容易的 public class example public static...

如何實現執行緒安全?

對於執行緒不安全的物件我們可以通過如下方法來實現執行緒安全 1 加鎖 利用synchronized或者reentrantlock來對不安全物件進行加鎖,來實現執行緒執行的序列化,從而保證多執行緒同時操作物件的安全性,乙個是語法層面的互斥鎖,乙個是api層面的互斥鎖.2 非阻塞同步來實現執行緒安全。原...

多執行緒無鎖演算法之無鎖佇列的實現

今天花了近兩個小時的時間好好的理解了一下多執行緒無鎖佇列的實現,檢視了很多資料和文獻。在我看來,實現無鎖佇列的關鍵點有二 1 各個平台的原子操作或者說cas原語 2 aba問題的理解和解決。首先來說說這個cas原語,所謂cas compare and swap 即比較並交換,在 intel 處理器中...