← Назад к вопросам

Что такое volatile в Android?

2.8 Senior🔥 151 комментариев
#JVM и память

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Volatile — ключевое слово для многопоточности в Java/Kotlin

Volatile — это модификатор переменной в Java (и Kotlin), который гарантирует видимость изменений переменной между потоками. Без volatile может возникнуть проблема: один поток меняет значение, но другой поток видит старое значение из кэша.

Проблема без volatile

// ❌ Проблема — без volatile
var flag: Boolean = false

fun thread1() {
    flag = true // Поток 1 меняет значение
}

fun thread2() {
    if (flag) { // Поток 2 может не увидеть изменение!
        println("Flag is true")
    }
}

Процессор может закэшировать значение flag в регистре или локальном кэше потока. Поток 2 прочитает старое значение (false) из кэша, не зная, что Поток 1 его изменил.

Решение с volatile

// ✅ Решение — с volatile
@Volatile
var flag: Boolean = false

fun thread1() {
    flag = true // Напрямую в память (main memory)
}

fun thread2() {
    if (flag) { // Чтение из памяти, не из кэша
        println("Flag is true")
    }
}

Volatile гарантирует:

  • Memory Visibility: изменение видно всем потокам
  • Atomicity: чтение/запись операция атомарна для примитивов и ссылок
  • Ordering: happens-before relationship между записью и чтением

Volatile vs Synchronized

// ❌ Синхронизация — слишком тяжелая, если нужна только видимость
synchronized(lock) {
    flag = true
}

// ✅ Volatile — легче, достаточно для видимости
@Volatile
var flag: Boolean = true

// Разница:
// - volatile: гарантирует видимость, НЕ гарантирует атомарность сложных операций
// - synchronized: гарантирует и видимость, и атомарность

Практические примеры в Android

1. Thread-safe флаг остановки:

class BackgroundTask {
    @Volatile
    private var shouldStop = false
    
    fun stop() {
        shouldStop = true // Рабочий поток увидит это мгновенно
    }
    
    fun run() {
        while (!shouldStop) { // Проверяет видимое значение
            // Работа
        }
    }
}

2. Состояние в многопоточном сервисе:

class LocationService {
    @Volatile
    private var isTracking = false
    
    fun startTracking() {
        isTracking = true
    }
    
    fun isTrackingNow(): Boolean = isTracking
}

3. Паттерн Double-Checked Locking:

class Singleton {
    companion object {
        @Volatile
        private var instance: Singleton? = null
        
        fun getInstance(): Singleton {
            if (instance == null) { // Первая проверка без синхронизации
                synchronized(this) {
                    if (instance == null) { // Вторая проверка с синхронизацией
                        instance = Singleton()
                    }
                }
            }
            return instance!!
        }
    }
}

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

Используй volatile когда:

  • Одна переменная меняется из разных потоков
  • Нужна видимость между потоками
  • НЕ нужна синхронизация сложных операций
  • Хочешь избежать оверхеда synchronized блоков

НЕ используй volatile когда:

  • Нужна атомарность составных операций (i++, check-then-act)
  • Работаешь со сложными объектами без внутренней синхронизации
  • Можно использовать готовые классы (AtomicBoolean, AtomicReference)

Альтернативы

// ✅ Вместо volatile для счётчика
val counter = AtomicInteger(0)
counter.incrementAndGet()

// ✅ Для references
val ref = AtomicReference<String>(null)
ref.set("value")

Вывод

Volatile — это инструмент для многопоточности, который гарантирует видимость переменной между потоками. Используй его для флагов, состояния и простых значений, которые меняются из разных потоков. Для сложных операций используй synchronized или AtomicXxx классы.

Что такое volatile в Android? | PrepBro