有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

需要java吗?

如果我有一个字节队列,其中预期有一个线程生产者,另一个消费者:

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仅由读卡器线程修改,
writeDX仅由writer线程执行

readIdx==writeIdx表示没有内容
并且队列最多只能占用buf。长度—1字节的数据

因为只有一个线程是一个整数状态的修饰符,所以是否需要挥发物,或者可以忽略挥发物

thx 坦率的


共 (3) 个答案

  1. # 1 楼答案

    Nathan是正确的,这并不是说两个线程会互相写变量,而是变量本身对于另一个线程(或者更确切地说是CPU内核)可能永远不可见

    有一个有趣的队列LMAX disruptor,它实际上使用非易失性变量让CPU更好地安排工作

  2. # 2 楼答案

    您应该声明它们volatile。 例如,让我们看看readIdx。如果它不是volatile,那么writer线程优化可以假设它从未更改过,并基于该假设进行错误的优化

    但是,我看不到您访问writer线程中的readIdx任何地方(或读取器线程中的writeIdx),只为分配给某个局部变量rd(或wr)。我只是假设有一些代码缺失或者你的问题没有真正意义

  3. # 3 楼答案

    如果另一个线程必须读取它,那么它需要是易失性的。volatile关键字向JVM指示不能缓存该值或对其更新进行重新排序,否则其他线程可能看不到对其值的更新

    可见性问题也扩展到了buf阵列。由于buf需要与索引同步更改,因此写入和读取方法似乎需要同步。同步使更改可见,并确保并发调用不会导致索引和buf内容变得不一致