[英]Is volatile needed?
如果我有一個字節隊列,它應該有一個線程生成器,另一個消費者:
class ByteQueue{
byte[] buf;
/*volatile?*/ int readIdx;
/*volatile?*/ int writeIdx;
Runnable writeListener;
Runnable readListener;
// ...
void write( byte[] b ){
int wr = writeIdx;
int rd = readIdx;
// check consistency and free space using wr+rd
// copy to buf, starting at wr, eventually wrap around
// update writeIdx afterwards
writeIdx = ( wr + b.length ) % buf.length;
// callback to notify consumer for data available
writeListener.run();
}
void read( byte[] b ){
int wr = writeIdx;
int rd = readIdx;
// check consistency and available data using wr+rd
// copy buf to b, starting at rd, eventually wrap around
// update readIdx afterwards
readIdx = ( rd + b.length ) % buf.length;
// callback to notify producer for free space available
readListener.run();
}
int available() { return (writeIdx - readIdx) % buf.length; }
int free() { return buf.length - available() -1; }
// ...
}
這種類型的隊列不需要同步。
readIdx僅由讀者線程修改,
writeIdx只由作者線程組成。
readIdx == writeIdx意味着,沒有內容。
並且隊列只能占用buf.length-1字節的數據。
是否需要揮發物或者是否可以省略它們,因為只有一個線程是一個整數狀態的修飾符?
弗蘭克
如果另一個線程必須讀取它,它需要是易失性的。 volatile
關鍵字向JVM指示無法緩存該值或重新排序其更新,否則其值的更新可能對其他線程不可見。
可見性問題也延伸到buf陣列。 由於buf需要隨索引一步改變,因此看起來需要同步write和read方法。 同步使更改可見,並確保並發調用不會導致索引和buf內容變得不一致。
你應該聲明它們是volatile
。 讓我們看看,例如,在readIdx
。 如果它不是volatile
,則編寫器線程優化可以假設它永遠不會被更改並基於該假設進行錯誤的優化。
但是,我沒有看到您在writeIdx
器線程(或讀取器線程中的readIdx
任何位置訪問readIdx
,除了分配給某個局部變量rd
(或wr
)。 我只是假設有一些代碼缺失或者你的問題沒有意義。
Nathan是正確的,並不是兩個線程會在每個其他線程上寫入變量,而是變量本身存在永遠不會對另一個線程(或者更確切地說是CPU核心) 可見的風險。
有一個有趣的隊列實際上使用非易失性變量讓CPU更好地安排工作,即LMAX干擾器 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.