[英]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.