java 易变变量_关于java:易变变量和其他变量
以下是經典Concurency in Practice的內容:
When thread A writes to a volatile variable and subsequently thread B
reads the same variable, the values of all variables that were
visible to A prior to writing to the volatile variable, become visible
to B after reading the volatile variable.
我不確定我是否真的能理解這一說法。 例如,在這種情況下,所有變量的含義是什么? 這是否意味著使用volatile也會對非易失性變量的使用產生副作用?
在我看來,這種說法具有我無法理解的一些微妙含義。
有什么幫助嗎?
您的問題的答案在JLS#17.4.5中:
A write to a volatile field (§8.3.1.4) happens-before every subsequent read of that field.
所以如果在一個線程中
aNonVolatileVariable = 2 //w1
aVolatileVariable = 5 //w2
然后在另一個線程中:
someVariable = aVolatileVariable //r1
anotherOne = aNonVolatileVariable //r2
您可以保證anotherOne等于2,即使該變量不是volatile。因此,是的,使用volatile對使用非易失性變量也有副作用。
更詳細地說,這是由于同一部分中的Java內存模型(JMM)提供了2個其他保證:線程內順序和可傳遞性(hb(x,y)表示x發生在y之前):
If x and y are actions of the same thread and x comes before y in program order, then hb(x, y).
[...]
If hb(x, y) and hb(y, z), then hb(x, z).
在我的示例中:
hb(w1,w2)和hb(r1,r2)(線程內語義)
hb(w2,r1)由于易失性保證
因此您可以通過傳遞性得出hb(w1,r2)的結論。
而且,JMM保證,如果程序與事前發生的關系正確同步,則該程序的所有執行將保持順序一致(即,看起來好像什么都沒有重新排序)。因此,在這種特定情況下,非易失性讀取可確保看到非易失性寫入的效果。
很抱歉,我無法從JSL的語句中看到這種保證,它只表示對volatile happens-before的寫操作讀取了該字段,這又如何保證在另一個線程中< x6>可見為2?
到目前為止,我理解hb(w1, r2) .Ok,但是為??什么在這里強制要求2的更新值可見?難道是,寫入發生在之前,但是讀取使用了一個緩存值而不是該值從w1開始?這是我無法獲得的部分。hb(w1, r2)的定義是否還包括可見性方面?
@Cratylus JMM保證正確同步的程序(具有先發生的關系)將保持順序一致:"對于程序員,這是極其有力的保證。[...]一旦確定代碼正確同步,程序員不必擔心重新排序會影響他或她的代碼。"
@Cratylus在同一部分中,JLS的另一句話是:"在一組一致的動作之前發生的情況下,每次讀取都會看到一個寫,該順序允許在順序發生之前看到它。"
這些說明不能解決由于重新排序而導致的不可見性嗎?不會進行重新排序,但是如何在寄存器中緩存值呢?
@Cratylus"順序一致"保證可見性。這是另一個引言(17.4.3):"順序一致性是對程序執行中的可見性和順序的非常有力的保證。在順序一致的執行中,所有單個動作(例如讀寫),這與程序的順序是一致的,并且每個動作都是原子的,每個線程都可以立即看到。"
這意味著如果您要寫入10個非易失性變量并寫入易失性變量,則必須在易失性變量之前設置所有非易失性變量。
如果您讀取了volatile變量和所有非易失性變量,則可以確保訂單不會被交換。
你在說什么順序?volatile變量不能重新排序,好,所以volatile變量不應該用非易失性重新演算并最后寫入,但是非易失性變量的順序可以還可以改變吧?
在易失性變量中設置的值的順序不能相對于其他變量(易失性或其他)更改,但是對于非易失性變量可能會發生這種情況。這意味著,當您設置易失性變量時,所有先前設置的值即使不是易失性的,也會被設置為緩存連貫的。
什么是緩存一致性?它們也不會被緩存?
它們將被緩存,但是CPU確保每個緩存看到相同的值(或將按需請求)。每個套接字具有2個或3個級別的多個緩存。它們具有通信總線,以確保它們在需要時彼此同步。甚至多個套接字也會通信以保持同步,從而避免了必須從主存儲器中寫入/讀取值的情況。
但是為什么非易失性變量需要并保證這種同步呢,僅僅因為它們恰好是在寫入volatile之前發生的,它們如何受到影響?
同步以一致的方式提供了更多的保證,例如讀取和寫入,例如增量。僅閱讀或寫作通常不是您所需要的。 volatile的定義使得在它之前發生的所有寫入都不得在它之后發生。
all writes which occur before it must not occur after it。我理解這一點,但這如何取決于/對緩存一致性產生副作用?這是我不關注的部分
我認為這里有些混亂。我見過很多人評論說,volatile關鍵字會影響第一級和第二級緩存等的處理器緩存一致性。我不知道這怎么可能是正確的。一方面,高速緩存一致性協議可確保同一內存位置的多個線程視圖始終保持同步。 VM更有可能為每個線程維護一個單獨的內存緩存區域,而volatile關鍵字調用一些用于同步它們的代碼。
JVM僅使用執行高速緩存一致性讀取和寫入的指令或不執行高速緩存一致性的簡單讀取和寫入的指令。它不執行CPU本身不支持的任何操作。此外,JVM可以優化非易失性字段的讀取方式,這意味著它們永遠不會看到更新,因為它們不會在同一線程中被更改。
彼得,我的意思是,我不認為您所指的緩存與處理器緩存相同。而是由VM維護的緩存。換句話說,如果兩個線程讀取兩個不同的值,則它們正在從兩個不同的內存地址讀取。如果兩個線程從同一地址讀取,則處理器緩存一致性協議將保證它們都接收相同的值。那是我的理解。如果我錯了,那么我想知道。
VM不維護此類緩存。當您從兩個不同的緩存中讀取相同的地址時,可以獲得不同的值。并非對所有CPU指令都強制執行緩存一致性。
總結
以上是生活随笔為你收集整理的java 易变变量_关于java:易变变量和其他变量的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ❤️六W字《计算机基础知识》(三)(建议
- 下一篇: linux修改密码最短生存时间,Linu