Атомные ссылки не нужны при использовании синхронизированных

Этот код взят из книги Фреда Лонга " Руководство по параллелизму Java ". Я понимаю, что группа атомарных операций не является атомарной операцией. Таким образом, приведенный ниже код не соответствует. Чтобы найти код, пожалуйста, посмотрите на страницу 23.

public class Adder {

    private AtomicReference<BigInteger> first;
    private AtomicReference<BigInteger> second;

    public Foo(BigInteger f, BigInteger s) {
        first = new AtomicReference<BigInteger>(f);
        second = new AtomicReference<BigInteger>(s);
    }

    public void update(BigInteger f, BigInteger s) {
        first.set(f);
        second.set(s);
    }

    public BigInteger add() {
        return first.get().add(second.get());
    }
}

И правильное решение выглядит так:

final class Adder {
    // ...
    public synchronized void update(BigInteger f, BigInteger s){
        first.set(f);
        second.set(s);
    }

    public synchronized BigInteger add() {
        return first.get().add(second.get());
    }
}

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

Так что мое решение будет выглядеть так:

public class Addrer {

    private BigInteger first;
    private BigInteger second;

    public Addrer(BigInteger f, BigInteger s) {
        first = f;
        second = s;
    }

    public synchronized void update(BigInteger f, BigInteger s) {
        first = f;
        second = s;
    }

    public synchronized BigInteger add() {
        return first.add(second);
    }
}

Я прав?

1 ответ

Решение

Вы должны сделать свой first а также second поля private и выставляют эти значения как синхронизированные методы. В противном случае непосредственное чтение полей может привести к устаревшим или частично устаревшим данным из BigInteger объекты (чтение энергонезависимых полей не является потокобезопасным). Тогда ваш класс будет потокобезопасным.

Вы можете попытаться сделать эти поля изменчивыми, но это не гарантирует атомарность вашего update или же add методы, как один поток может обновить одно поле только в середине вашего update или же add выполнение метода в другом потоке.

public class Adder {
    private BigInteger first;
    private BigInteger second;

    public Adder(BigInteger f, BigInteger s) {
        first = f;
        second = s;
    }

    public synchronized BigInteger getFirst() {
        return first;
    }

    public synchronized BigInteger getSecond() {
        return second;
    }

    public synchronized void update(BigInteger f, BigInteger s) {
        first = f;
        second = s;
    }

    public synchronized BigInteger add() {
        return first.add(second);
    }
}
Другие вопросы по тегам