Атомарность
Атомарность в контексте многопоточного программирования означает, что операция выполняется как единое целое, неделимо. Другими словами, атомарная операция либо выполняется полностью, либо не выполняется вовсе, и нет промежуточных состояний, которые могут быть видны другим потокам.
Атомарные операции помогают решить проблемы гонок данных (race conditions) и некорректного доступа к общим ресурсам в многопоточной среде. Основные проблемы, которые решаются с помощью атомарности:
Atomic
классы в Java, такие как AtomicInteger
, AtomicLong
, AtomicReference
и т.д., Atomic - принцип работы для соответствующих типов данных.
AtomicInteger
AtomicInteger
предоставляет атомарные операции для работы с целочисленными значениями.
import java.util.concurrent.atomic.AtomicInteger
val atomicCounter = AtomicInteger(0)
fun main() {
val threads = List(100) {
Thread {
repeat(1000) {
atomicCounter.incrementAndGet() // Атомарная операция
}
}
}
threads.forEach { it.start() }
threads.forEach { it.join() }
println(atomicCounter.get()) // Ожидаем 100000
}
В этом примере incrementAndGet()
является атомарной операцией, которая безопасно увеличивает значение переменной atomicCounter
на 1. Это предотвращает гонки данных и гарантирует корректный результат.
AtomicBoolean
AtomicBoolean
предоставляет атомарные операции для работы с логическими значениями.
import java.util.concurrent.atomic.AtomicBoolean
val atomicFlag = AtomicBoolean(false)
fun main() {
val threads = List(10) {
Thread {
if (atomicFlag.compareAndSet(false, true)) {
println("Thread ${Thread.currentThread().name} set the flag to true")
} else {
println("Thread ${Thread.currentThread().name} found the flag already true")
}
}
}
threads.forEach { it.start() }
threads.forEach { it.join() }
}
В этом примере compareAndSet(false, true)
проверяет текущее значение atomicFlag
и устанавливает его в true
, если текущее значение false
. Эта операция атомарна и гарантирует, что только один поток сможет изменить значение флага.
AtomicReference
AtomicReference
предоставляет атомарные операции для работы с объектами.
import java.util.concurrent.atomic.AtomicReference
data class User(val name: String, val age: Int)
val atomicUser = AtomicReference(User("John", 25))
fun main() {
val threads = List(10) {
Thread {
val updatedUser = User("John", atomicUser.get().age + 1)
atomicUser.set(updatedUser) // Атомарная операция
}
}
threads.forEach { it.start() }
threads.forEach { it.join() }
println(atomicUser.get()) // Ожидаем, что возраст увеличится на 10
}
В этом примере atomicUser.set(updatedUser)
является атомарной операцией, которая безопасно обновляет ссылку на объект User
. Это предотвращает гонки данных при обновлении ссылки на объект.
synchronized
), так как они используют низкоуровневые примитивы синхронизации.