Как синхронизировать коллекции
В Kotlin для синхронизации коллекций между потоками можно использовать несколько подходов.
synchronized
и стандартных коллекцийimport kotlin.concurrent.thread
val list = mutableListOf<String>()
val lock = Any()
fun addItem(item: String) {
synchronized(lock) {
list.add(item)
}
}
fun getItem(index: Int): String? {
return synchronized(lock) {
list.getOrNull(index)
}
}
fun main() {
// Поток 1
thread {
repeat(10) {
addItem("Item $it from Thread 1")
println("Thread 1 added item $it")
}
}
// Поток 2
thread {
repeat(10) {
addItem("Item $it from Thread 2")
println("Thread 2 added item $it")
}
}
// Дадим потокам время на выполнение
Thread.sleep(1000)
// Вывод содержимого коллекции
println("Final list: $list")
}
В этом примере доступ к коллекции list
синхронизирован через объект lock
, чтобы избежать одновременного доступа из нескольких потоков.
java.util.concurrent
Если вам нужна коллекция, которая уже поддерживает синхронизацию, вы можете использовать коллекции из java.util.concurrent
. Например, CopyOnWriteArrayList
:
import java.util.concurrent.CopyOnWriteArrayList
import kotlin.concurrent.thread
val list = CopyOnWriteArrayList<String>()
fun addItem(item: String) {
list.add(item)
}
fun getItem(index: Int): String? {
return list.getOrNull(index)
}
fun main() {
// Поток 1
thread {
repeat(10) {
addItem("Item $it from Thread 1")
println("Thread 1 added item $it")
}
}
// Поток 2
thread {
repeat(10) {
addItem("Item $it from Thread 2")
println("Thread 2 added item $it")
}
}
// Дадим потокам время на выполнение
Thread.sleep(1000)
// Вывод содержимого коллекции
println("Final list: $list")
}
CopyOnWriteArrayList
автоматически синхронизирует доступ и создаёт копии массива при изменениях, что делает её подходящей для сценариев, когда изменения происходят редко, а чтения часты.
import kotlinx.coroutines.*
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
val list = mutableListOf<String>()
val mutex = Mutex()
suspend fun addItem(item: String) {
mutex.withLock {
list.add(item)
}
}
suspend fun getItem(index: Int): String? {
return mutex.withLock {
list.getOrNull(index)
}
}
fun main() = runBlocking {
// Поток 1
val job1 = launch {
repeat(10) {
addItem("Item $it from Coroutine 1")
println("Coroutine 1 added item $it")
}
}
// Поток 2
val job2 = launch {
repeat(10) {
addItem("Item $it from Coroutine 2")
println("Coroutine 2 added item $it")
}
}
// Ожидание завершения обоих потоков
joinAll(job1, job2)
// Вывод содержимого коллекции
println("Final list: $list")
}
В этом случае Mutex
обеспечивает безопасный доступ к коллекции из разных корутин. Использование withLock
гарантирует, что только один поток (или корутина) может выполнять критическую секцию кода в один момент времени.