Java-массивы: синхронизированный + атомарный * или синхронизированный достаточно?

Этот вопрос задавался снова и снова, но у меня все еще есть сомнения. Когда люди говорят, что synchronized создает барьер памяти, к чему относится этот барьер памяти, к ЛЮБОЙ кешированной переменной? Это не выглядит возможным.

Итак, из-за этого сомнения я написал код, который выглядит следующим образом:

final AtomicReferenceArray<Double> total=new AtomicReferenceArray<Double>(func.outDim);
for(int i=0; i<func.outDim; i++) total.set(i, 0.);
for(int i=0; i<threads; i++){
    workers[i]=new Thread(new Runnable(){
        public void run() {
            double[] myPartialSum=new double(func.outDim);
            //some lengthy math which fills myPartialSum...

            //The Atomic* guarantees that I'm not writing local copies of the Double references (whose value are immutables, so it's like an array of truly volatile doubles) in variable total, synchronized(total) atomizes the sum
            synchronized(total){ for(int i=0; i<func.outDim; i++) total.set(i, total.get(i)+myPartialSum[i]); }
        };
    workers[i].start();
}
//wait for workers to terminate...

//print results accessing total outside of a synchronized(total) block, since no worker is alive at this point.

Интересно, можно ли просто заменить тип итога простым double[]: для этого потребуется, чтобы synchronized(total) (в методе run()) гарантировал, что я не работаю с локальными копиями каждого индекса в массив двойников, то есть ограничение памяти не относится только к значению total сам (который находится под капотом указатель), но к индексам total тоже. Это происходит?

2 ответа

Решение

Барьер памяти применяется ко всем ссылкам памяти, даже не связанным. Когда вы синхронизируете total вы увидите актуальную копию любых значений памяти, а когда вы покинете блок, появится еще один барьер памяти.

Если мое понимание верно synchronized(total) будет синхронизировать любой доступ к total и, следовательно, должен синхронизировать доступ (чтение и запись) к значениям в массиве тоже.

Так как double массив непосредственно содержит значения вместо ссылок, которые не должны быть доступны другим потокам во время выполнения синхронизированного блока. Если у вас есть массив объектов, вы не сможете изменить ссылки в массиве, но вы все равно можете получить доступ к самим объектам.

Другие вопросы по тегам