简体   繁体   中英

Is volatile needed?

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.

You should declare them volatile . Let's look, for example, at readIdx . If it it not volatile , writer thread optimization can assume it is never changed and make wrong optimizations based on that assumption.

However, I don't see that you access readIdx anywhere in writer thread (or writeIdx in reader thread) apart for assignment to some local variable rd (or wr ). I just assume there is some code missing or otherwise your question doesn't really make sense.

Nathan is correct, it's not that the two threads would write over each others variables, but that the variables themselves would risk to never be visible for the other thread (or rather CPU-core).

There is an interesting queue that actually uses non-volatile variables to let the CPU better schedule the work, the LMAX disruptor .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM