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

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

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

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

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

6 ответов


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

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


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

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


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

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


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

volatile long num;
num = num+1

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

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


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

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

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


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

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

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

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