[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"question-mnogopotochnost-v-chyom-razlichiya-mezhdu-volatile-i-atomic-peremennymi":3},{"id":4,"slug":5,"topicId":6,"topicSlug":7,"topicName":8,"topicEmoji":9,"question":10,"answer":11,"codeLang":12,"codeSrc":12,"important":12,"commonMistakes":12,"modernUsage":12,"difficulty":13,"tags":14,"related":21,"progress":22,"seo":23},250,"v-chyom-razlichiya-mezhdu-volatile-i-atomic-peremennymi",8,"mnogopotochnost","Многопоточность","🔀","В чём различия между volatile и Atomic переменными?","\u003C!-- grade: 3\u002F5 — суть передана, но нет деталей по реализации и нет примера -->\n\n### volatile\n\nМодификатор `volatile` гарантирует **видимость** изменений переменной для всех потоков и запрет переупорядочивания, но **не гарантирует атомарность** составных операций. Операция `count++` над `volatile int count` по-прежнему состоит из трёх шагов (чтение текущего значения, инкремент, запись нового значения), и между ними другой поток может вмешаться.\n\n### Atomic-переменные\n\nКлассы пакета `java.util.concurrent.atomic` (такие как `AtomicInteger`, `AtomicLong`, `AtomicBoolean`, `AtomicReference` и другие) обеспечивают **атомарность** составных операций за счёт использования низкоуровневых CAS-инструкций (Compare-And-Swap) процессора. Они также гарантируют видимость, как и `volatile`.\n\n### Сравнение\n\n| Характеристика | `volatile` | `Atomic*` |\n|---|---|---|\n| Видимость | Да | Да |\n| Атомарность чтения\u002Fзаписи | Да (для примитивов и ссылок) | Да |\n| Атомарность read-modify-write | **Нет** | **Да** (`getAndIncrement()`, `compareAndSet()` и т.д.) |\n| Механизм | Memory barrier | CAS (Compare-And-Swap) без блокировок |\n| Блокировка потока | Нет | Нет (lock-free) |\n| Подходит для счётчиков | Нет (race condition) | Да |\n| Подходит для флагов | Да | Избыточно (достаточно `volatile`) |\n\n### Пример: небезопасный volatile-счётчик vs безопасный AtomicInteger\n\n\u003Cdetails>\n\u003Csummary>Пример: сравнение volatile и AtomicInteger\u003C\u002Fsummary>\n\n```java\npublic class VolatileVsAtomic {\n    private volatile int volatileCounter = 0;\n    private final AtomicInteger atomicCounter = new AtomicInteger(0);\n\n    \u002F\u002F НЕ потокобезопасно! count++ — не атомарная операция\n    public void unsafeIncrement() {\n        volatileCounter++;\n    }\n\n    \u002F\u002F Потокобезопасно: CAS-операция атомарна\n    public void safeIncrement() {\n        atomicCounter.incrementAndGet();\n    }\n\n    public static void main(String[] args) throws InterruptedException {\n        VolatileVsAtomic demo = new VolatileVsAtomic();\n        int threadCount = 100;\n        int incrementsPerThread = 1000;\n\n        ExecutorService executor = Executors.newFixedThreadPool(threadCount);\n        for (int i = 0; i \u003C threadCount; i++) {\n            executor.submit(() -> {\n                for (int j = 0; j \u003C incrementsPerThread; j++) {\n                    demo.unsafeIncrement();\n                    demo.safeIncrement();\n                }\n            });\n        }\n        executor.shutdown();\n        executor.awaitTermination(10, TimeUnit.SECONDS);\n\n        \u002F\u002F volatile: скорее всего \u003C 100_000 (потеряны инкременты)\n        System.out.println(\"volatile: \" + demo.volatileCounter);\n        \u002F\u002F atomic: всегда ровно 100_000\n        System.out.println(\"atomic:   \" + demo.atomicCounter.get());\n    }\n}\n```\n\n\u003C\u002Fdetails>\n\n### Как работает CAS\n\nОперация Compare-And-Swap выполняется на уровне процессора за одну инструкцию:\n\n1. Прочитать текущее значение переменной.\n2. Вычислить новое значение.\n3. Записать новое значение **только если** текущее значение не изменилось с момента чтения. Если изменилось -- повторить с шага 1.\n\nЭто позволяет обойтись без блокировок (lock-free), но при высокой конкуренции может вызвать «спин» -- поток многократно повторяет попытки CAS.\n\n> **Аналогия из жизни.** `volatile` -- это табло на стене: все видят актуальное число, но если два человека одновременно хотят увеличить число, один из них «затрёт» обновление другого. `AtomicInteger` -- это табло с контролем: человек берёт текущее число, вычисляет новое и перевешивает табличку, но только если никто не успел изменить число до него. Если кто-то уже изменил -- он смотрит заново и повторяет попытку.\n\n> **На собеседовании.** Ключевой момент: объясните, что `volatile` достаточно для простых флагов (один пишет -- все читают), но для счётчиков и других read-modify-write операций нужны `Atomic*`-классы. Бонусный ответ: упомяните `LongAdder` (Java 8+), который при высокой конкуренции работает быстрее `AtomicLong` за счёт разделения значения на ячейки (striped).","","middle",[15,16,17,18,19,20],"CAS","AtomicInteger","Atomic","volatile","атомарность","concurrency",[],null,{"title":24,"description":25,"ogTitle":26,"ogDescription":27,"keywords":28,"schemaAnswer":33,"featuredSnippetReady":34},"volatile vs Atomic в Java — в чём разница — Gymterview","volatile гарантирует видимость, но не атомарность составных операций. Atomic-классы (AtomicInteger и др.) обеспечивают атомарные операции через CAS.","volatile vs Atomic — видимость и атомарность","volatile обеспечивает видимость переменной, но count++ не станет атомарным. AtomicInteger.getAndIncrement() — атомарная замена инкремента.",[29,30,31,32],"volatile vs Atomic Java","AtomicInteger volatile разница","атомарность Java","CAS Java","volatile принуждает использовать единственный экземпляр переменной, но не гарантирует атомарность. Операция count++ не станет атомарной от volatile. Atomic-классы (AtomicInteger и др.) предоставляют атомарные методы вроде getAndIncrement() на основе CAS-операций.",true]