Volatile vs synchronized в Java: особенности чтения и записи

Пройдите тест, узнайте какой профессии подходите

Я предпочитаю
0%
Работать самостоятельно и не зависеть от других
Работать в команде и рассчитывать на помощь коллег
Организовывать и контролировать процесс работы

Быстрый ответ

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

Пример:

Java
Скопировать код
private volatile boolean isStopped = false;

Synchronized, в свою очередь, предоставляет взаимное исключение, позволяя методу или блоку кода выполняться только одному потоку. Этот механизм отлично подходит для атомарных операций и работы с несколькими переменными.

Пример:

Java
Скопировать код
public synchronized void safeAction() {
    // Действия внутри защищены от одновременного доступа
}

Кратко говоря, volatile применяется для простой синхронизации отдельных переменных, в то время как synchronized обеспечивает потокобезопасность составных операций.

Кинга Идем в IT: пошаговый план для смены профессии

Основы синхронизации

Понимание volatile

Переменные volatile гарантируют, что каждый поток видит актуальное значение переменной, предотвращая её локальное кеширование без необходимости блокировки.

Осмысление synchronized

Synchronized же обеспечивает атомарность действий, блокируя доступ к ресурсу. Методы и блоки кода, объявленные как synchronized, работают так, как будто все механизмы в них идеально сработали без коллизий.

Volatile против synchronized

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

Когда использовать volatile или synchronized

Пример использования одной переменной

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

Пример использования нескольких переменных или составной операции

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

Выбор между производительностью и безопасностью

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

Продвинутые инструменты синхронизации

Явные блокировки с помощью инструментов управления конкуренцией

Пакет java.util.concurrent.locks предоставляет расширенный контроль над блокировками, включая такие инструменты, как ReentrantLock и ReadWriteLock.

Атомарные переменные для операций с одной переменной

Пакет java.util.concurrent.atomic предлагает потокобезопасные операции для работы с отдельными переменными, не требующими блокировки. Он поддерживает такие операции, как CAS (Compare-and-swap).

Реальные сценарии

Предпочтение volatile: Игры и прямые трансляции

В ситуациях, требующих мгновенного отклика, например, в играх и живых трансляциях, volatile обеспечивает быстрое отображение актуального состояния системы.

Активное применение synchronized: Финансы и сложные рабочие процессы

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

Модель "чтение-запись-обновление" от Лоренса Дола

Модель, предложенная Лоренсом Долом, сочетает использование volatile для операций чтения, synchronized для операций записи и явные блокировки для операций обновления, чтобы достичь оптимального баланса производительности.

Визуализация

Volatile можно представить как офисное уведомление о новых изменениях:

// До использования volatile
Поток 1: 🗂️ ---> видит чертеж v1
Поток 2: 🗂️ ---> видит чертеж v1
// Обновление без использования volatile
Поток 1: 🗂️ ---> все еще видит чертеж v1 🙉
Поток 2: 🗂️ ---> может увидеть чертеж v2 ✅

Synchronized работает по принципу очереди в магазине:

// С переходом на synchronized
Один поток в одно время может воспользоваться ресурсом:
🍬🔒 Поток 1: 🍭 радуется конфете
🍬🔒 Поток 2: 😴 ждет своей очереди...
🍬🔒 Поток 1 закончил: 👋
🍬🔒 Поток 2: 🍭 получил свой шанс!

volatile: Текущее значение ➡️ Все сразу видят последние изменения

synchronized: Очередность ➡️ Каждый получает доступ к ресурсу по очереди

Полезные материалы

  1. Глава 17. Потоки и блокировки (Спецификация языка Java) — официальные документы о потоках и блокировках в Java.
  2. java.util.concurrent (Java Platform SE 8) — подробное руководство о механизмах управления конкуренцией.
  3. Java Concurrency in Practice — классическая книга Брайана Гоэтца, которую стоит изучить.
  4. IBM Developer – Теория и практика Java: Управление волатильностью — Глубокий анализ механизма volatile в модели памяти Java.