簡體   English   中英

volatile 與最終字段性能

[英]volatile vs final fields performance

什么更適合性能? 假設沒有或幾乎沒有爭用

  1. 具有可變字段並一一更新的可變類
  2. 具有最終字段的不可變類,更新周期避免了多字段更新,而是重新創建類一次

波動性在每次寫入時都需要內存屏障,我想最終字段也是如此? 意思是對象構造時的單個內存屏障?

更新澄清:

考慮到 java 內存模型和當前的硬件,我覺得這個問題本身很有價值,並且一般可以回答。 如果您必須假設具體情況:

  • 該對象當然是從多個線程訪問的,否則這個練習將毫無意義
  • 單個對象是長期存在的,就像在幾個小時內一樣
  • 這些對象有成百上千個,每秒有成百上千個更新事件

final提示編譯器字段值不能更改。 在編譯時捕獲任何寫入嘗試。 讀取final值不使用內存屏障。 您不能寫入final變量,因此內存屏障是沒有意義的。

使用提示,編譯器(或 JIT)可以用常量替換對最終值的內存引用。 所以在性能方面, final不會引入任何額外的開銷。

對於易失性字段,要使易失性字段的更新值在所有訪問它的線程之間保持一致,需要在運行時進行協調。 使用volatile引入了必須執行的不變式。

對於不可變的對象,成本是復制對象以反映更改。 存在限制復制量的方法,例如使用持久性數據結構 同樣,當您擁有不可變的對象時,您可以進行基於值的比較,並使用諸如備忘錄之類的技術來返回已緩存的實例。

因此,每種方法都可能會損害性能,具體取決於您正在執行的操作。

關於不變方法更好的主要事情是它更干凈,更容易推理。 對於可變對象,整個身份概念變得晦暗

命令式程序直接操縱其世界(例如內存)。 它建立在一個現在不可持續的單線程前提下-當您查看或更改世界時,世界就停止了。 您說“做到這一點”,它就會發生,“改變這一點”,它就會發生變化。 命令式編程語言主要圍繞執行/執行操作以及更改內存位置。

即使在多線程之前,這也不是一個好主意。 添加並發,您就會遇到一個真正的問題,因為“世界已停止”的前提已經不再成立,並且恢復幻覺非常困難且容易出錯。 多個參與者(每個參與者的行為似乎無所不能)必須以某種方式避免破壞其他參與者的假設和影響。 這需要互斥鎖和鎖,以封鎖每個參與者要操縱的區域,並需要大量開銷才能將更改傳播到共享內存,以便其他內核可以看到它們。 效果不是很好。

可變狀態方法使您的代碼容易受到競爭條件和死鎖的影響。 減少可變狀態的數量可以減少您遭受這些錯誤的可能性。

如果垃圾收集器在上次訪問舊對象和為新對象提供可用空間之間刷新每個線程的緩存,並且如果沒有緩存行包含來自多個對象的數據,那么在大多數平台上自然不可能一個新構造的對象在對該對象的引用存儲在該線程可訪問的位置之前加載到任何線程的緩存中,即使沒有任何讀取障礙(超出前面提到的每 GC 循環一次系統) -寬障礙)。 此外,如果編譯器可以判斷一個對象的多個字段將發生寫入,而不會對任何其他可能已公開其引用的對象進行任何干預寫入,則它可以省略除最后一個之外的所有對象的寫入屏障。

唯一一次使用final字段會比volatile更昂貴,如果它需要創建更多對象來處理可以使用volatile字段“就地”完成的更改。 由於許多因素會影響對象創建成本,因此在特定系統的特定環境下判斷哪種方法更有效的唯一可靠方法通常是對兩者進行基准測試。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM