Подтвердить что ты не робот

Атомные операции и многопоточность

Недавно я читал учебник, в котором я встретил выражение, в котором говорится.

"Спецификация языка Java гарантирует, что чтение или запись переменной является атомной операцией (если только переменная не имеет тип long или double). Операционные переменные типа long или double являются только атомарными, если они объявлены с ключевым словом volatile.

AtomicInteger или AtomicLong, который предоставляет методы, такие как getAndDecrement(), getAndIncrement() и getAndSet(), которые являются атомарными.

Я немного смутился с вышеупомянутым утверждением.. и не могли бы вы прояснить , когда использовать классы AtomicInteger или AtomicLong.

4b9b3361

Ответ 1

Выполнение a = 28a как en int) является атомной операцией. Но выполнение a++ не является атомной операцией, потому что для этого требуется чтение значения a, приращения и записи в результат. В результате, если вы использовали a++ для реализации поточно-защищенного счетчика, вы могли бы иметь два потока, считывающих значение одновременно (например, 26), а затем увеличивать его и записывать одновременно, в результате получается 27, вместо 28.

AtomicInteger решает эту проблему, предоставляя атомные операции, такие как те, которые вы указали. В моем примере вы, например, использовали бы incrementAndGet(), который гарантировал бы, что конечное значение равно 28, а не 27.

Ответ 2

Atomic означает, что операция завершается без какой-либо возможности для чего-то между ними. например. getAndDecrement(), на AtomicInteger, гарантирует, что переменная будет возвращена и уменьшена одновременно.

Если бы это была не атомная операция, существовала бы вероятность того, что значение будет уменьшаться (например, от 3 до 2), а затем изменено другим потоком (например, изменив его с 2 на 5), затем вернется как 5.

Ответ 3

Вам нужно AtomicInteger, если вам нужно прочитать переменную и записать результат в зависимости от значения чтения. Например, i++ читает i (например, 3) и записывает i+1 (например, 4). Тем временем поток может быть прерван, а три других потока увеличивают i. Теперь, когда мы вернемся, i имеет значение 6, но наш поток все еще записывает 4, основываясь на том, что он читал заранее.

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

Ответ 4

Я думаю, что это означает, что операция с длинным и двойным чтением является атомарной, а операция записи является атомарной. Но чтение + запись не является атомарным.

volatile long num;
num = num+1

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

Чтобы сделать его потокобезопасным, вам нужно использовать AtomicLong и использовать функцию getAndIncrement.

Ответ 5

Вы используете int или long, основываясь на верхнем/нижнем пределе диапазона номеров, с которым имеете дело. Пожалуйста, не смешивайте неатомное поведение с AtomicLong. Все, что вы написали выше, правильно, но вы, вероятно, смешиваете обе концепции. AtomicXXX более полезны в тех случаях, когда вы выполняете "сравнение и набор" операций. Например, даже если int может быть изменен/прочитан, атомарно следующий код будет неправильным в многопоточной среде:

int i =10
..
..
..
if(i == 10) i++;

в многопоточной среде два потока могут получить доступ к этому коду с атомарным и обновленным значением я и сделать его в согласованном состоянии. SO справляется с такими ситуациями, как правило, вы защищаете код "if (i == 10) я ++;" с синхронизированным блоком. Однако класс AtomicInteger предоставляет API для достижения таких целей без использования синхронизированных блоков, которые работают медленнее. То же самое относится к API-интерфейсам AtmoicLong

Ответ 6

атомарность операции требуется, когда вы мутируете переменную. Выполнение int a = 10; - это атомная операция, но не та, которая даст вам проблему. операции с заданием обычно являются мутационными типами, такими как a++ или a = a + 2; и т.д.

Спецификация Java гарантирует, что "чтение" и "запись" являются атомарными операциями, а не их комбинациями. поэтому операция, которая "читает, добавляет 1, а затем записывает результат назад", не является атомарной согласно спецификации. такие операции называются составными операциями, и они обычно должны быть атомарными в контексте их использования в нашем коде.

Атомные типы помогают решить эту проблему. используя incrementAndget() для атомарного типа, делает "чтение", добавляет 1, а затем записывает результат назад и считывает новый результат "одна атомная операция в контексте безопасности потоков".

Надеюсь, это поможет. Кстати, вы должны прочитать это (http://walivi.wordpress.com/2013/08/24/concurrency-in-java-a-beginners-introduction/) статью об основах concurrency и потоков. это прекрасно объясняет этот материал.