Является ли присвоение и вычисление значения функции атомарной операцией? - PullRequest
2 голосов
/ 03 августа 2011

Я хочу знать, является ли вычисление значения функции и присвоение результата переменной атомарной операцией в Java.

Например:

У меня есть потокобезопасная очередь с приоритетами q. В q я сохраняю элементы, и каждый элемент имеет rank, в соответствии с которым он помещается в очередь. Кроме того, у меня есть общая переменная topRank, которая всегда должна содержать ранг самого верхнего элемента в q. Следующий код выполняется параллельно по числу потоков:

element = q.remove(); // do something with element
topRank = q.peek();

может случиться так, что threadA удалит один элемент из q и вычислит значение q.peek(), а непосредственно перед присвоением его topRank будет прерван threadB, тогда threadB удалит еще один элемент из q обновление topRank. И тогда threadA возобновит присвоение неправильного значения topRank.

Ссылка на официальную литературу была бы очень признательна.

Спасибо.

Ответы [ 4 ]

4 голосов
/ 03 августа 2011

Короткий ответ: эти операции НЕ являются атомарными, и вам нужно записать синхронизацию в ваш код. Это ОГРОМНАЯ тема, и о написании многопоточных программ можно многое узнать. Google для "безопасности потока Java" и "многопоточности Java".

1 голос
/ 03 августа 2011

Потоковая безопасность относится только к операции в вызовах remove() или peek(). Если вы не предпримете шаги, чтобы заблокировать потоки от гонок друг с другом, гонка с topRank вполне возможна.

Для получения дополнительной информации посмотрите учебник по синхронизации Java .

0 голосов
/ 03 августа 2011

Расчет значения функции не может быть атомарным.Функция может работать годами, прежде чем вернуть значение.

0 голосов
/ 03 августа 2011

1) Я не думаю, что существуют атомарные операции, если вы не защищаете их (синхронизация и другие технические приемы).

2) При этом это не относится к вашему примеру.

В вашем примере у вас есть.

a) Звоните q.remove()

b) q.remove() делает свою работу (потокобезопасно или нет).

c) q.remove() возвращает результат

d) Результат присваивается element (это назначение !! все до этого только вычисляли значение для назначения).


Итак,это не только если присваивание (последний шаг в вашей операции) является атомарным или нет, вы должны убедиться, что q.remove () тоже атомарное.И я уверяю вас, что это не так.

Поскольку это не потокобезопасно, если вы хотите избежать одновременного доступа, вы должны синхронизировать весь блок.


РЕДАКТИРОВАТЬ, отвечая на комментарии авторов.

Итак, что вы спрашиваете, если каким-то образом q.peek() вернет элемент, но другой закончится в topRank из-за того, что другой поток связался с ним, не так ли?

Если толькоtopRank совместно используется разными потоками, это невозможно:

a) q.peek() выполняет свою логику

b) возвращаемое значение q.peek() копируется (сохраняется встек, обратно к выражению, которое называется q.peek())

c) q.peek() выход.Только теперь другие экземпляры могут получить доступ к синхронизированному разделу для изменения q.state, но возвращаемое значение уже скопировано в стек.

d) Копия в стеке присвоена topRank

...