3 回答

TA貢獻(xiàn)1797條經(jīng)驗(yàn) 獲得超6個(gè)贊
顯然,寫入 l 會(huì)阻止寫入 k 的重新排序,但它會(huì)阻止寫入 i 和 j 的重新排序嗎?
重新排序的含義并不完全清楚;看我上面的評(píng)論。
然而,在Java 5+內(nèi)存模型,我們可以說,寫入i
和j
所發(fā)生之前,寫入l
將是另一個(gè)線程可見后已經(jīng)閱讀l
......只要沒有寫i
和j
寫后l
。
這確實(shí)會(huì)限制寫入i
和的指令的任何重新排序j
。具體來說,它們不能在寫入后的內(nèi)存寫入屏障之后移動(dòng)到l
,因?yàn)檫@可能導(dǎo)致它們對(duì)第二個(gè)線程不可見。
但這項(xiàng)禁令的范圍是什么?
本身沒有禁令。
您需要了解指令、重新排序和內(nèi)存屏障只是實(shí)現(xiàn) Java 內(nèi)存模型的特定方式的細(xì)節(jié)。該模型實(shí)際上是根據(jù)保證在任何“格式良好的執(zhí)行”中可見的內(nèi)容來定義的。
據(jù)我了解, volatile 會(huì)阻止在使用它的塊內(nèi)重新排序,對(duì)嗎?
實(shí)際上,沒有。塊不考慮。重要的是方法中語句的(程序源代碼)順序。
@Stephen C 說,volatile 保證發(fā)生在整個(gè)方法主體內(nèi)部的行為之前,即使在封閉塊中,但我找不到任何確認(rèn)。
確認(rèn)是 JLS 17.4.3。它聲明如下:
在每個(gè)線程 t 執(zhí)行的所有線程間動(dòng)作中,t 的程序順序是一個(gè)總順序,它反映了根據(jù) t 的線程內(nèi)語義執(zhí)行這些動(dòng)作的順序。
如果所有動(dòng)作以與程序順序一致的總順序(執(zhí)行順序)發(fā)生,則一組動(dòng)作是順序一致的,此外,變量 v 的每次讀取 r 都會(huì)看到寫入 w 寫入 v 的值,使得:
w 在執(zhí)行順序中排在 r 之前,并且
在執(zhí)行順序中,沒有其他寫入 w' 使得 w 在 w' 之前并且 w' 在 r 之前。
順序一致性是對(duì)程序執(zhí)行中的可見性和順序的非常有力的保證。在順序一致的執(zhí)行中,所有單獨(dú)的動(dòng)作(例如讀取和寫入)都有一個(gè)與程序順序一致的總順序,每個(gè)單獨(dú)的動(dòng)作都是原子的,對(duì)每個(gè)線程都是立即可見的。
如果一個(gè)程序沒有數(shù)據(jù)競(jìng)爭(zhēng),那么程序的所有執(zhí)行都將看起來是順序一致的。
請(qǐng)注意,此定義中沒有提及塊或范圍。

TA貢獻(xiàn)1111條經(jīng)驗(yàn) 獲得超0個(gè)贊
我很想知道 volatile 變量如何影響其他字段
易失性變量確實(shí)會(huì)影響其他字段。如果 JIT 編譯器認(rèn)為重新排序不會(huì)對(duì)執(zhí)行輸出產(chǎn)生任何影響,則可以對(duì)指令重新排序。因此,如果您有 6 個(gè)獨(dú)立變量存儲(chǔ),則 JIT 可以重新排序指令。
但是,如果您將變量設(shè)為 volatile,即在您的情況下為變量l,那么 JIT 將不會(huì)在 volatile STORE 之后重新排序任何變量 STORES。我認(rèn)為這是有道理的,因?yàn)樵诙嗑€程程序中,如果我將變量l的值設(shè)為 4,那么我應(yīng)該將i設(shè)為 1,因?yàn)樵谖业某绦蛑校?strong>我是在l之前編寫的,最終是程序順序語義(如果我是沒有錯(cuò))。
Note that volatile variables does two things:
編譯器不會(huì)在易失性存儲(chǔ)之后重新排序任何存儲(chǔ)/在易失性讀取之前不會(huì)重新排序任何讀取。
刷新加載/存儲(chǔ)緩沖區(qū),以便所有處理器都可以看到更改。
編輯:
這里的好博客:http : //jpbempel.blogspot.com/2013/05/volatile-and-memory-barriers.html
添加回答
舉報(bào)