在Java中对Singleton类进行双重检查锁定
Singleton類(lèi)在Java開(kāi)發(fā)人員中非常常見(jiàn),但是它給初級(jí)開(kāi)發(fā)人員帶來(lái)了許多挑戰(zhàn)。 他們面臨的主要挑戰(zhàn)之一是如何使Singleton保持為Singleton? 也就是說(shuō),無(wú)論出于何種原因,如何防止單個(gè)實(shí)例的多個(gè)實(shí)例。 對(duì)Singleton進(jìn)行雙重檢查鎖定是一種確保在應(yīng)用程序生命周期中僅創(chuàng)建Singleton類(lèi)的一個(gè)實(shí)例的方法。 顧名思義,在雙重檢查鎖定中,代碼對(duì)一個(gè)Singleton類(lèi)的現(xiàn)有實(shí)例進(jìn)行兩次檢查(有和沒(méi)有鎖定以進(jìn)行兩次檢查),以確保不會(huì)創(chuàng)建一個(gè)以上的singleton實(shí)例。 順便說(shuō)一句,它在Java修復(fù)JDK 1.5中的內(nèi)存模型問(wèn)題之前就被打破了。 在本文中,我們將看到如何在Java中為Singleton的雙重檢查鎖定編寫(xiě)代碼 ,為什么在Java 5之前雙重檢查鎖定被破壞以及如何解決。 順便說(shuō)一句,從訪談的角度來(lái)看,這也很重要,我聽(tīng)說(shuō)有人要求對(duì)金融和服務(wù)業(yè)的公司進(jìn)行手工雙重檢查Singleton鎖定的代碼,并相信我很棘手,直到您清楚地了解了什么你在做。 您也可以查看我的Singleton設(shè)計(jì)模式問(wèn)題的完整列表,以進(jìn)行良好的準(zhǔn)備。
Singleton類(lèi)破壞其合同的一種常見(jiàn)情況是多線程。 如果您要求初學(xué)者為Singleton設(shè)計(jì)模式編寫(xiě)代碼,那么他很有可能會(huì)提出以下內(nèi)容:
private static Singleton _instance;public static Singleton getInstance() {if (_instance == null) {_instance = new Singleton();}return _instance; }并且當(dāng)您指出這段代碼將由多個(gè)線程并行調(diào)用時(shí),將創(chuàng)建Singleton類(lèi)的多個(gè)實(shí)例時(shí),他可能會(huì)使整個(gè)getInstance()方法同步化 ,如第二個(gè)代碼示例getInstanceTS()方法所示。 盡管它是線程安全的,可以解決多個(gè)實(shí)例的問(wèn)題,但效率不是很高。 每次調(diào)用此方法時(shí),都需要承擔(dān)同步的費(fèi)用,而創(chuàng)建Singleton實(shí)例時(shí),僅在第一類(lèi)上才需要同步。 這將使我們進(jìn)入雙重檢查的鎖定模式 ,其中只有關(guān)鍵的代碼段被鎖定。 程序員稱(chēng)其為“雙重檢查鎖定”,因?yàn)閷?duì)_instance == null進(jìn)行了兩次檢查,一次沒(méi)有鎖定,而另一次則帶有鎖定(內(nèi)部同步)塊。 這是Java中經(jīng)過(guò)雙重檢查的鎖定的樣子:
public static Singleton getInstanceDC() {if (_instance == null) { // Single Checkedsynchronized (Singleton.class) {if (_instance == null) { // Double checked_instance = new Singleton();}}}return _instance; }
從表面上看,這種方法看起來(lái)很完美,因?yàn)槟恍枰獮橥綁K支付一次費(fèi)用,但是在使_instance變量volatile之前,它仍然無(wú)效。 如果沒(méi)有volatile修飾符,則Java中的另一個(gè)線程可能會(huì)看到_instance變量的一半初始化狀態(tài),但是由于volatile變量保證了before-before關(guān)系的發(fā)生,所有寫(xiě)入都會(huì)在_instance變量的任何讀取之前發(fā)生在volatile _instance上。 在Java 5之前不是這種情況,這就是為什么以前雙重檢查鎖定已被破壞的原因。 現(xiàn)在,有了事前保證 ,您可以放心地認(rèn)為這將起作用。 順便說(shuō)一下,這不是創(chuàng)建線程安全的Singleton的最佳方法,您可以將Enum用作Singleton ,它在實(shí)例創(chuàng)建期間提供內(nèi)置的線程安全性。 另一種方法是使用靜態(tài)持有人模式。
這就是Java中對(duì)Singleton類(lèi)的雙重檢查鎖定 。 這是在Java中創(chuàng)建線程安全的Singleton的有爭(zhēng)議的方法之一,就將Enum用作Singleton類(lèi)而言,還有其他更簡(jiǎn)單的選擇。 我不建議您像那樣實(shí)現(xiàn)Singleton,因?yàn)橛性S多更好的方法可以在Java中實(shí)現(xiàn)Singleton模式。 但是,這個(gè)問(wèn)題具有歷史意義,并且還教導(dǎo)了并發(fā)如何引入細(xì)微的錯(cuò)誤。 正如我之前所說(shuō),從訪談的角度來(lái)看,這非常重要。 在進(jìn)行任何Java面試之前,練習(xí)手動(dòng)編寫(xiě)Singleton類(lèi)的雙重檢查鎖定。 這將使您深入了解Java程序員的編碼錯(cuò)誤。 與此相關(guān)的是,在現(xiàn)代的測(cè)試驅(qū)動(dòng)開(kāi)發(fā)中,由于Singleton難以模擬其行為,因此Singleton被視為反模式,因此,如果您是TDD實(shí)踐者,最好避免使用Singleton模式。
翻譯自: https://www.javacodegeeks.com/2014/05/double-checked-locking-on-singleton-class-in-java.html
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的在Java中对Singleton类进行双重检查锁定的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Win10系统的Edge浏览器开启兼容模
- 下一篇: 使用jXLS将Excel文件解析为Jav