Несоответствующее состояние сравнения Java - PullRequest
0 голосов
/ 02 июня 2018

В Параллелизм Java на практике приведен пример *, демонстрирующий проблему видимости , когда два разных потока могут не видеть досостояние даты любого конкретного изменяемого объекта из-за отсутствия синхронизации.

public class Holder {
    private int n;
    public Holder(int n) { this.n = n; }

    public void assertSanity() {
        if (n != n){
            throw new AssertionError("This statement is false.");
        }
    }

В этом конкретном примере книга заявляет, что поток «А» должен сначала инициализироваться и опубликовать его через небезопасный поток, например:

public Holder holder;
public void initialize() {
    holder = new Holder(42);
}

А затем поток "B" вызывает holder.assertSanity(), что вполне возможно, что AssertionError будет брошен из-за несовместимого состояния.

Теперь,Я понимаю основную предпосылку аргумента, когда изменение, сделанное в изменяемой переменной, никогда не может наблюдаться другим потоком.Но что меня смущает, так это то, что он сравнивает одну и ту же (или я так думаю) ссылку n != n.

Разве это не сравнивает значение изменяемого примитивного поля private int n?Независимо от того, что n теперь может иметь значение 42 для потока A и значение 0 (по умолчанию) для потока B, не должен быть прямой вызов для проверки его значения в том же потоке *1023*. соответствует ?т. е. вызов assertSanity() в потоке A проверит, если 42 != 42, а в потоке B 0 != 0?

* Ссылка на 3.5 Safe Publication, листинги 3.14 и 3.15 в книге.

Ответы [ 2 ]

0 голосов
/ 02 июня 2018

Во время сравнения в потоке B n != n, B извлекает n два раза.Между тем конструктор работает в потоке A и изменит значение n со значения по умолчанию до 42.

0 голосов
/ 02 июня 2018

Проблема в том, что в выражении n != n переменная n будет загружена дважды (при условии отсутствия оптимизации байт-кода).Между этими двумя нагрузками другой поток может изменить значение.

...