【问题标题】:does array elements need to be volatile? if so, how can I make it?数组元素是否需要易变?如果是这样,我该怎么做?
【发布时间】:2015-02-12 20:56:24
【问题描述】:

假设我有这样的小代码:

public class Test {
    final Data[] dataArray;
    final int maxSize;
    volatile long nextWriteNo;
    volatile long nextReadNo;

    public Test(int maxSize){
        this.dataArray = new Data[maxSize];
        this.maxSize = maxSize;
        this.nextWriteNo = 0L;
        this.nextReadNo = 0L;
    }

    public void write(Data data){
        synchronized (this) {
            dataArray[(int)(nextWriteNo & (maxSize - 1))] = data;
            nextWriteNo = nextWriteNo + 1L;
        }
    }

    public Data read(Data data){
        synchronized (this) {
            Data data = dataArray[(int)(nextReadNo & (maxSize -1))];
            nextReadNo= nextReadNo + 1L;
            return data;
        }
    }
}

其中一个线程会多次调用write()方法,而另一个线程会多次调用read()方法。 write() 方法更新数组,而 read 方法读取数组。一切都发生在synchronized 块内。所以为了可见性,或者发生在关系之前,数组元素(对象引用)是否需要volatile?如果是这样,我该怎么做?

【问题讨论】:

    标签: java concurrency visibility atomic


    【解决方案1】:

    没有理由在同步块内使用volatile。块本身保证值的状态在读取和写入之间保持一致。

    【讨论】:

    • 只是一个小补充:同步块意味着对“这个线程内存”的所有更改在块完成后对所有其他线程都是可见的
    • 我在问线程缓存。是否会从一个线程对数组元素进行更新,立即对其他线程可见,而无需使其易失性?
    • 是的,引用本身将对其他线程可见,而不会发生变化。但不是引用实例的状态。那里的任何更新都需要单独同步。
    • 抱歉,不太清楚 :(。假设调用 write() 将第 0 个元素中的值从 null 更改为对象引用,在调用 read() 或其他线程时,该对象引用会立即对其他线程可见吗?线程可能仍然看到 null 吗?
    • “但不是引用实例的状态。” 我不确定你在这里想说什么。 synchronized 保证在其中触及的所有状态的一致性。我认为您的答案文本很好。没有理由在正确同步的情况下使用 volatile。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-08
    • 2013-12-22
    • 2013-04-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多