Это может показаться педантизмом, но на самом деле я сомневаюсь в своих фундаментальных предположениях .. :)

В java-документации по синхронизированным методам есть следующий пример. :

public class SynchronizedCounter {
    private int c = 0;

    public synchronized void increment() {
        c++;
    }

    public synchronized void decrement() {
        c--;
    }

    public synchronized int value() {
        return c;
    }
}

Действительно ли ключевое слово synchronized требуется для метода value? Конечно, это атомарно, и будет ли значение извлечено до или после любых вызовов связанных методов в других потоках, не имеет большого значения? Достаточно ли следующего:

public class SynchronizedCounter {
    private int c = 0;

    public synchronized void increment() {
        c++;
    }

    public synchronized void decrement() {
        c--;
    }

    public int value() {
        return c;
    }
}

Я понимаю, что в более сложном случае, когда осуществляется доступ к нескольким частным переменным, да, это было бы важно, но в этом простом случае можно ли предположить, что это можно упростить?

Кроме того, я полагаю, что существует риск того, что в будущих модификациях может потребоваться синхронизация метода значения, и об этом можно будет забыть, что приведет к ошибкам и т. Д., Поэтому, возможно, это в какой-то мере считается защитным программированием, но я игнорирую этот аспект здесь ... :)

0
Mark 26 Окт 2015 в 21:42

2 ответа

Лучший ответ

Да, синхронизация действительно требуется на value(). В противном случае поток может вызвать value() и получить устаревший ответ.

Наверняка это атомарно

Что касается целых чисел, я так считаю, но если значение было long или double, это не так. Можно даже увидеть только некоторые биты в обновленном поле!

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

Зависит от вашего варианта использования. Часто это имеет значение.

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

4
dkatzel 26 Окт 2015 в 18:47

Synchronized требуется как для чтения, так и для записи переменной из другого потока. Это гарантирует

  1. эти значения будут скопированы из кеша или регистров в ОЗУ (при условии, что это важно для записи, а не чтения)

  2. он устанавливает, что записи будут происходить до чтения, если они появляются в коде. В противном случае компилятор может изменить порядок строк байт-кода для оптимизации.

Проверьте Эффективная Java , элемент 66 для более подробного анализа.

2
Manos Nikolaidis 26 Окт 2015 в 18:49