избыточный энергозависимый в дешевой блокировке чтения-записи? - PullRequest
0 голосов
/ 11 мая 2018

Брайан Гетц в своей статье от https://www.ibm.com/developerworks/java/library/j-jtp06197/

использует пример, вставленный ниже, как дешевую блокировку чтения-записи. Мой вопрос заключается в том, что если значение переменной int не объявлено как volatile, будет ли это иметь значение? Насколько я понимаю, поскольку запись в значение выполняется в синхронизированном блоке, поэтому последнее значение в любом случае будет видно другим потокам, и поэтому объявление его изменчивым является избыточным. Просьба уточнить?

@ThreadSafe
public class CheesyCounter {
// Employs the cheap read-write lock trick
// All mutative operations MUST be done with the 'this' lock held
@GuardedBy("this") private volatile int value;

public int getValue() { return value; }

public synchronized int increment() {
    return value++;
}

}

Ответы [ 3 ]

0 голосов
/ 11 мая 2018

Насколько я понимаю, поскольку запись в значение выполняется в синхронизированном блоке, поэтому последнее значение в любом случае будет видно другим потокам

Это неверно. Как правило, нет никакой гарантии, что другие потоки «увидят» изменения в переменных, как только они будут внесены. Поток может видеть устаревшее значение для измененной переменной, потому что, например, поток видит значение в регистре, а не в основной памяти.

Переменная volatile устанавливает семантику "происходит до". JLS, раздел 17.4.5 , состояния:

С помощью отношения случай-до можно заказать два действия. Если одно действие происходит до другого, то первое видно и упорядочено до второго.

  • Запись в поле volatile (§8.3.1.4) происходит до при каждом последующем чтении этого поля.

JLS, раздел 8.3.1.4 :

Поле может быть объявлено volatile, и в этом случае Модель памяти Java гарантирует, что все потоки увидят согласованное значение для переменной (§17.4).

Причина, по которой поле должно быть volatile, заключается в том, что, хотя чтение является атомарным, оно должно гарантировать, что значение является текущим - что любое значение, ранее записанное другим потоком, является видимым. Чтение, являющееся атомарным, недостаточно; volatile все еще необходимо для обеспечения согласованности значения.

0 голосов
/ 12 мая 2018

Большое спасибо за ответы, ребята.Обнаружил это и на веб-сайте Oracle: «Во-вторых, при выходе из синхронизированного метода он автоматически устанавливает отношение« до и после »с любым последующим вызовом синхронизированного метода для того же объекта».https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html

0 голосов
/ 11 мая 2018
public synchronized int increment()

Это synchronized не позволяет пропускать приращение, если два или более потоков пытались увеличить приращение одновременно (поскольку ++ не является атомарным).

private volatile int value

Это предотвращает просмотр устаревшего значения в одном потоке, которое уже было увеличено в другом потоке. (Обратите внимание, что мы могли бы также сделать синхронизацию getValue для достижения этой цели)

...