不使用synchronized和lock,如何實現(xiàn)一個線程安全的單例?(二)
如果不那么吹毛求疵的話,可以使用枚舉、靜態(tài)內(nèi)部類以及餓漢模式來實現(xiàn)單例模式。見:不使用synchronized和lock,如何實現(xiàn)一個線程安全的單例? 但是,上面這幾種方法其實底層也都用到了synchronized,那么有沒有什么辦法可以不使用synchronized和lock,如何實現(xiàn)一個線程安全的單例?
答案是有的,那就是CAS。關(guān)于CAS,我博客中專門有一篇文章介紹過他,很多樂觀鎖都是基于CAS實現(xiàn)的。這里簡單介紹一下,詳細(xì)內(nèi)容見 樂觀鎖的一種實現(xiàn)方式——CAS
CAS是項樂觀鎖技術(shù),當(dāng)多個線程嘗試使用CAS同時更新同一個變量時,只有其中一個線程能更新變量的值,而其它線程都失敗,失敗的線程并不會被掛起,而是被告知這次競爭中失敗,并可以再次嘗試。
在JDK1.5 中新增java.util.concurrent(J.U.C)就是建立在CAS之上的。相對于對于synchronized這種阻塞算法,CAS是非阻塞算法的一種常見實現(xiàn)。所以J.U.C在性能上有了很大的提升。
借助CAS(AtomicReference)實現(xiàn)單例模式:
- public class Singleton {
- private static final AtomicReference<Singleton> INSTANCE = new AtomicReference<Singleton>();
- private Singleton() {}
- public static Singleton getInstance() {
- for (;;) {
- Singleton singleton = INSTANCE.get();
- if (null != singleton) {
- return singleton;
- }
- singleton = new Singleton();
- if (INSTANCE.compareAndSet(null, singleton)) {
- return singleton;
- }
- }
- }
- }
代碼比較簡單,稍微了解一下AtomicReference的原理就可以看得懂。不了解的建議去看下,了解下這些CAS的實現(xiàn)。
用CAS的好處在于不需要使用傳統(tǒng)的鎖機(jī)制來保證線程安全,CAS是一種基于忙等待的算法,依賴底層硬件的實現(xiàn),相對于鎖它沒有線程切換和阻塞的額外消耗,可以支持較大的并行度。
CAS的一個重要缺點在于如果忙等待一直執(zhí)行不成功(一直在死循環(huán)中),會對CPU造成較大的執(zhí)行開銷。
【本文是51CTO專欄作者Hollis的原創(chuàng)文章,作者微信公眾號Hollis(ID:hollischuang)】