国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Java并發,volatile+不可變容器對象能保證線程安全么?!

tyheist / 2528人閱讀

摘要:同樣,用類型的變量來保存這些值也不是線程安全的。僅保證可見性,無法保證線程安全性。并且返回的結果是對象,是局部變量,并未使對象逸出,所以這里也是線程安全的。

《Java并發編程實戰》第3章原文 《Java并發編程實戰》中3.4.2 示例:使用Volatile類型來發布不可變對象

在前面的UnsafeCachingFactorizer類中,我們嘗試用兩個AtomicReferences變量來保存最新的數值及其因數分解結果,但這種方式并非是線程安全的,因為我們無法以原子方式來同時讀取或更新這兩個相關的值。同樣,用volatile類型的變量來保存這些值也不是線程安全的。然而,在某些情況下,不可變對象能提供一種弱形式的原子性。
因式分解Servlet將執行兩個原子操作:更新緩存的結果,以及通過判斷緩存中的數值是否等于請求的數值來決定是否直接讀取緩存中的因數分解結果。每當需要對一組相關數據以原子方式執行某個操作時,就可以考慮創建一個不可變的類來包含這些數據,例如程序清單3-12中的OneValueCache。

程序清單 3-12 對數值及其因數分解結果進行緩存的不可變容器類
@Immutable  
class OneValueCache {  
   private final BigInteger lastNumber;  
   private final BigInteger[] lastFactors;  
 
   public OneValueCache(BigInteger i,  
                        BigInteger[] factors) {  
       lastNumber  = i;  
       lastFactors = Arrays.copyOf(factors, factors.length);  
   }  
 
   public BigInteger[] getFactors(BigInteger i) {  
       if (lastNumber == null || !lastNumber.equals(i))  
           return null;  
       else  
           return Arrays.copyOf(lastFactors, lastFactors.length);  
   }  
} 

對于在訪問和更新多個相關變量時出現的競爭條件問題,可以通過將這些變量全部保存在一個不可變對象中來消除。如果是一個可變的對象,那么就必須使用鎖來確保原子性。如果是一個不可變對象,那么當線程獲得了對該對象的引用后,就不必擔心另一個線程會修改對象的狀態。如果要更新這些變量,那么可以創建一個新的容器對象,但其他使用原有對象的線程仍然會看到對象處于一致的狀態。
程序清單3-13中的VolatileCachedFactorizer使用了OneValueCache來保存緩存的數值及其因數。當一個線程將volatile類型的cache設置為引用一個新的OneValueCache時,其他線程就會立即看到新緩存的數據。

程序清單 3-13 使用指向不可變容器對象的volatile類型引用以緩存最新的結果
@ThreadSafe  
public class VolatileCachedFactorizer implements Servlet {  
   private volatile OneValueCache cache =  
       new OneValueCache(null, null);  
 
   public void service(ServletRequest req, ServletResponse resp) {  
       BigInteger i = extractFromRequest(req);  
       BigInteger[] factors = cache.getFactors(i);  
       if (factors == null) {  
           factorfactors = factor(i);  
           cache = new OneValueCache(i, factors);  
       }  
       encodeIntoResponse(resp, factors);  
   }  
} 

與cache相關的操作不會相互干擾,因為OneValueCache是不可變的,并且在每條相應的代碼路徑中只會訪問它一次。
通過使用包含多個狀態變量的容器對象來維持不變性條件,并使用一個volatile類型的引用來確保可見性,使得VolatileCachedFactorizer在沒有顯式地使用鎖的情況下仍然是線程安全的。

分析

程序清單3-13中存在『先檢查后執行』(Check-Then-Act)的競態條件。

OneValueCache類的不可變性僅保證了對象的原子性。

volatile僅保證可見性,無法保證線程安全性。

綜上,對象的不可變性+volatile可見性,并不能解決競態條件的并發問題,所以原文的這段結論是錯誤的。

更新

疑惑已經解決了。

結論:
cache對象在service()中只有一處寫操作(創建新的cache對象),其余都是讀操作,這里符合volatile的應用場景,確保cache對象對其他線程的可見性,不會出現并發讀的問題。并且返回的結果是factors對象,factors是局部變量,并未使cache對象逸出,所以這里也是線程安全的。

該問題已經提交到提問區和知乎:
https://segmentfault.com/q/10...
https://www.zhihu.com/questio...

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/66397.html

相關文章

  • 線程基礎必要知識點!看了學習多線程事半功倍

    摘要:是需要我們去處理很多事情,為了防止多線程給我們帶來的安全和性能的問題下面就來簡單總結一下我們需要哪些知識點來解決多線程遇到的問題。 前言 不小心就鴿了幾天沒有更新了,這個星期回家咯。在學校的日子要努力一點才行! 只有光頭才能變強 回顧前面: 多線程三分鐘就可以入個門了! Thread源碼剖析 本文章的知識主要參考《Java并發編程實戰》這本書的前4章,這本書的前4章都是講解并發的基...

    YPHP 評論0 收藏0
  • Java并發編程實戰」之對象的共享

    摘要:當某個不應該發布的對象被發布時,這種情況被稱為逸出。線程安全共享線程安全的對象在其內部實現同步,因此多線程可以通過對象的公有接口來進行訪問而不需要進一步的同步。 前言   本系列博客是對《Java并發編程實戰》的一點總結,本篇主要講解以下幾個內容,內容會比較枯燥。可能大家看標題不能能直觀的感受出到底什么意思,這就是專業術語,哈哈,解釋下,術語(terminology)是在特定學科領域用...

    phodal 評論0 收藏0
  • 【J2SE】java并發編程實戰 讀書筆記( 一、二、三章)

    摘要:發布的對象內部狀態可能會破壞封裝性,使程序難以維持不變性條件。不變性線程安全性是不可變對象的固有屬性之一。可變對象必須通過安全方式來發布,并且必須是線程安全的或者有某個鎖保護起來。 線程的優缺點 線程是系統調度的基本單位。線程如果使用得當,可以有效地降低程序的開發和維護等成本,同時提升復雜應用程序的性能。多線程程序可以通過提高處理器資源的利用率來提升系統的吞吐率。與此同時,在線程的使用...

    QLQ 評論0 收藏0
  • 學習Java線程的一些總結

    摘要:多線程環境下的一些問題安全性問題在沒有正確同步的情況下,多線程環境下程序可能得出錯誤的結果。一些相關概念競爭條件多線程的環境下,程序執行的結果取決于線程交替執行的方式。而線程的交替操作順序是不可預測的,如此程序執行的結果也是不可預測的。 入口 Java多線程的應用復雜性之如jvm有限的幾個內存方面的操作和規范,就像無數紛繁復雜的應用邏輯建立在有限的指令集上。 如何寫出線程安全的程序,有...

    coolpail 評論0 收藏0
  • Akka系列(四):Akka中的共享內存模型

    摘要:共享內存相信對并發有所了解的同學都應該知道在推出后,對內存管理有了更高標準的規范了,這使我們開發并發程序也有更好的標準了,不會有一些模糊的定義導致的無法確定的錯誤。 通過前幾篇的學習,相信大家對Akka應該有所了解了,都說解決并發哪家強,JVM上面找Akka,那么Akka到底在解決并發問題上幫我們做了什么呢? 共享內存 眾所周知,在處理并發問題上面,最核心的一部分就是如何處理共享內存,...

    baukh789 評論0 收藏0

發表評論

0條評論

tyheist

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<