Вызов метода и атомарность - PullRequest
2 голосов
/ 07 февраля 2011

У меня есть метод с одной атомарной операцией, такой как этот

int value;

public void setValue(int value) {
    this.value = value;
}

тогда я называю это очевидным образом, как

foo.setValue(10);

Вопрос в том, будет ли это атомная операция? Если нет, какие атомарные операции будут выполнены? Как я могу проверить это на своем компьютере (если смогу)?

Ответы [ 3 ]

11 голосов
/ 07 февраля 2011

Да,

this.value = value;

операция атомарная. См. Спецификация языка Java: потоки и блокировки .

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

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

  • делает метод синхронизированным,
  • , допустив переменную или
  • используйте AtomicInteger из пакета java.util.concurrent. (предпочтительный способ имо)

Следует также отметить, что операция не будет атомарной, если вы изменили с int на long или double. Вот соответствующий раздел из JLS:

17,4 Неатомарная обработка двойной и длинной

Если переменная типа double или long не объявлена ​​как volatile, то для действий загрузки, сохранения, чтения и записи они обрабатываются так, как если бы они были двумя переменными по 32 бита каждая: везде, где правила требуют одного из этих действий выполняются два таких действия, по одному для каждой 32-битной половины.


Некоторые полезные ссылки:

1 голос
/ 07 февраля 2011

Прежде всего, присваивание всем примитивным типам (кроме 64-битных) в Java является атомарным в соответствии со спецификацией Java. Но, например, автоинкремент не является потокобезопасным, независимо от того, какой тип вы используете.

Но настоящая проблема с этим кодом - не атомарность, а видимость. Если два потока изменяют value, они могут не видеть изменения, сделанные друг другом. Используйте ключевое слово volatile или, что еще лучше, AtomicInteger, чтобы гарантировать правильную синхронизацию и видимость.

Обратите внимание, что ключевое слово synchronized также гарантирует видимость, что означает, что если в блоке synchronnized произойдет какая-либо модификация, гарантируется, что оно будет видно другим потокам.

1 голос
/ 07 февраля 2011

Это атомарное, потому что это просто примитивное 32-битное значение.

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

Если бы это было long, у вас не было бы такой же гарантии, хотя на практике большинство реализаций виртуальных машин действительно long записывает как атомарные операции.

Вот что JLS говорит по этому вопросу:

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

Но с интсами вы в безопасности, вопрос в том, достаточно ли вам этой слабой гарантии? Чаще всего ответ - нет.

...