if I have a byte queue, where it is expected to have one thread producer, another consumer:
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; }
// ...
}
This type of queue should not need synchronization.
readIdx is only modified by reader thread,
writeIdx only by the writer thread.
readIdx == writeIdx means, there is no content.
And the queue can only take up to buf.length-1 bytes of data.
Are the volatiles needed or can they be omitted because only one thread is the modifier of one integer state?
thx Frank
If another thread has to read it, it needs to be volatile. The volatile
keyword indicates to the JVM that the value can't be cached or have its updates reordered, otherwise updates to its value may not be visible to other threads.
The visibility concern extends to the buf array too. Since buf needs to change in step with the indexes it would seem like the write and read methods need to be synchronized. Synchronization makes the changes visible and makes sure that concurrent calls don't result in the indexes and buf contents becoming inconsistent.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With