摘要:在構建一個對象的過程中,更要考慮到多線程間共享數據的一致性問題,否則很可能會發生一個在線程中構建完整的對象,在線程中看到的卻只被構建了一部分。例如下面的代碼上面的代碼本意是想實現一個單例模式,但在多線程環境下,這個單例模式將很容易被打破。
在上一篇文章《從Java多線程可見性談Happens-Before原則》中,我們詳細討論了在并發編程中Happens-Before原則對多線程共享變量的重要性。要想確保讓一個線程對共享變量的修改能被其它線程感知到,就必須讓兩個線程中的操作滿足Happens-Before原則。
在構建一個對象的過程中,更要考慮到多線程間共享數據的一致性問題,否則很可能會發生一個在A線程中構建完整的對象,在B線程中看到的卻只被構建了一部分。例如下面的代碼:
public class UnsafeLazyInitialization { private static Resource resource; public static Resource getInstance() { if(resource == null) { resource = new Resource(); } return resource; } }
上面的代碼本意是想實現一個單例模式,但在多線程環境下,這個單例模式將很容易被打破。
首先,resource是一個普通變量,當一個線程更新resource變量的值時,其它線程可能無法感知到resource引用已經指向了一個創建好的對象,所以可能會導致程序創建多個Resource對象。
更糟糕的是重排序,在線程A中是先初始化Resource對象的各個field之后再將resource引用設置為指向它,線程B看到的可能是對引用變量resource的寫入操作在對Resource對象各個field的寫入操作之前發生。這會導致線程B看到的是一個被部分構造的Resource對象實例,該對象可能處于無效狀態。
為了解決上面的問題,我們可以套用Happens-Before規則。例如在getInstance方法上聲明synchronized。
然而對于構建一個對象實例的操作,除了可以使用Happens-Before原則外,我們利用下面兩種方式也可以保證對象的構建狀態被正確發布到其它線程。
靜態初始化器是由JVM在類的初始化階段執行,即在類被加載后并且被線程使用前。在靜態初始化期間,內存寫入操作將自動對所有線程可見。所以上面的程序改下成如下代碼將會確保Resource對象被正確發布到其它線程:
public class EagerInitialization { private static Resource resource = new Resource(); public static Resource getInstance() { return resource; } }含有final域的對象
對于含有final域的對象,初始化安全性可以防止對對象引用的寫入操作被重排序到對象構造過程之前。在構造函數完成時,構造函數對final域的所有寫入操作,以及通過final域可以到達的任何變量的寫入操作,都能夠被獲取到該對象引用的線程看到。例如下面的代碼:
public class FinalInitialization { private static final Resource resource; public static Resource getInstance() { if(resource == null) { resource = new Resource(); } return resource; } }
在上面的代碼中,將resource變量聲明為final類型的。這樣可以保證,無論哪個線程,只要獲取到對象的引用的值,就一定可以看到一個被完整構建的Resource對象。
但是此處的resource引用變量本身仍然需要其他機制保證可以對其它線程可見。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/67704.html
摘要:多線程環境下的一些問題安全性問題在沒有正確同步的情況下,多線程環境下程序可能得出錯誤的結果。一些相關概念競爭條件多線程的環境下,程序執行的結果取決于線程交替執行的方式。而線程的交替操作順序是不可預測的,如此程序執行的結果也是不可預測的。 入口 Java多線程的應用復雜性之如jvm有限的幾個內存方面的操作和規范,就像無數紛繁復雜的應用邏輯建立在有限的指令集上。 如何寫出線程安全的程序,有...
摘要:下面是線程相關的熱門面試題,你可以用它來好好準備面試。線程安全問題都是由全局變量及靜態變量引起的。持有自旋鎖的線程在之前應該釋放自旋鎖以便其它線程可以獲得自旋鎖。 最近看到網上流傳著,各種面試經驗及面試題,往往都是一大堆技術題目貼上去,而沒有答案。 不管你是新程序員還是老手,你一定在面試中遇到過有關線程的問題。Java語言一個重要的特點就是內置了對并發的支持,讓Java大受企業和程序員...
摘要:包含了支持服務開發的類,并為提供基礎,如語言基礎操作操作網絡通信以及多線程等技術。在運行文件時,的解釋器對這些字節碼進行解釋執行,執行過程中需要加入的類在連接階段被載入到運行環境中。支持多個線程同時執行,并提供多線程之間的同步機制。 1.什么是Java語言 簡單地說,Java 是由 Sun Microsystems 公司于 1995 年推出的一門面向對象程序設計語言。2009 年 Or...
閱讀 1076·2021-11-22 14:56
閱讀 1520·2019-08-30 15:55
閱讀 3359·2019-08-30 15:45
閱讀 1655·2019-08-30 13:03
閱讀 2868·2019-08-29 18:47
閱讀 3334·2019-08-29 11:09
閱讀 2641·2019-08-26 18:36
閱讀 2615·2019-08-26 13:55