Какие еще знаете механизмы синхронизации данных, кроме synchronized?android-216

В Android-разработке существует множество механизмов для потокобезопасной работы с данными, каждый со своими особенностями и сценариями применения.

1. Lock интерфейсы из java.util.concurrent.locks

ReentrantLock

Более гибкая альтернатива synchronized с возможностью:

  • Честного распределения блокировок
  • Проверки состояния блокировки
  • Таймаутов при ожидании
val lock = ReentrantLock()
fun safeIncrement() {
    lock.lock()
    try {
        // Критическая секция
        counter++
    } finally {
        lock.unlock() // Всегда в finally!
    }
}

ReadWriteLock

Оптимизация для read-heavy сценариев:

  • Множественные чтения параллельно
  • Эксклюзивная блокировка для записи
val rwLock = ReentrantReadWriteLock()

fun readData(): String {
    rwLock.readLock().lock()
    try {
        return sharedData
    } finally {
        rwLock.readLock().unlock()
    }
}

2. Атомарные классы

Для простых атомарных операций без полной блокировки:

val atomicCounter = AtomicInteger(0)

fun increment() {
    atomicCounter.incrementAndGet()
    // Или сложные операции:
    atomicCounter.updateAndGet { it + 2 }
}

3. Корутины с Mutex

Для асинхронного кода в корутинах:

val mutex = Mutex()
var sharedData = 0

suspend fun safeUpdate() {
    mutex.withLock {
        sharedData++ // Приостанавливает, а не блокирует поток
    }
}

4. Thread-safe коллекции

Готовые реализации из java.util.concurrent:

  • ConcurrentHashMap
  • CopyOnWriteArrayList
  • BlockingQueue и ее реализации
val concurrentMap = ConcurrentHashMap<String, Int>()
concurrentMap.compute("key") { _, v -> (v ?: 0) + 1 }

5. Flow с stateIn/shareIn

Для реактивного подхода:

val sharedFlow = someFlow
    .stateIn(
        scope = viewModelScope,
        started = SharingStarted.WhileSubscribed(5000),
        initialValue = 0
    )

6. Другие механизмы

Volatile

Для гарантии видимости изменений между потоками (но не атомарности):

@Volatile
var flag = false

Double-Checked Locking

Оптимизированный вариант для ленивой инициализации:

val lazyValue: SomeType by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
    SomeType()
}

Критерии выбора механизма

  1. Гранулярность блокировки:

    • Fine-grained (ConcurrentHashMap) vs Coarse-grained (synchronized)
  2. Тип операций:

    • Read-heavy (ReadWriteLock) vs Write-heavy (Mutex)
  3. Контекст выполнения:

    • Блокирующий код (ReentrantLock) vs Асинхронный (Mutex)
  4. Производительность:

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

Резюмируем:

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