Действие под замком в Kotlin
Повторять try и finally на каждом
участке утомительно. Расширение withLock
берет замок, выполняет лямбду и снимает замок
даже при исключении внутри блока.
Сигнатура читается как «под этим Mutex сделай
шаги внутри фигурных скобок». Тело лямбды -
тот же критический участок, что раньше лежал
между lock и unlock:
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
suspend fun credit(guard: Mutex, balance: IntArray, sum: Int) {
guard.withLock {
balance[0] += sum
}
}
Несколько корутин могут звать одну такую функцию:
каждый вызов дождется своей очереди под замком.
Счетчик orders растет без ручного
finally:
import kotlinx.coroutines.joinAll
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
fun main() {
runBlocking {
var orders = 0
val guard = Mutex()
val jobs = List(2) {
launch {
repeat(400) {
guard.withLock {
orders++
}
}
}
}
joinAll(*jobs.toTypedArray())
println(orders)
}
}
Один Mutex можно передать в несколько
функций: каждая оборачивает свой фрагмент в
withLock, и очередь остается общей:
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
suspend fun take(guard: Mutex, box: IntArray) {
guard.withLock {
box[0]--
}
}
suspend fun give(guard: Mutex, box: IntArray) {
guard.withLock {
box[0]++
}
}
Поле stock типа Int и общий
Mutex. Две корутины по 250
раз уменьшают запас на единицу внутри
блока под замком. После ожидания выведите
остаток.
Сумма weight в массиве из одного
элемента. Три фоновые задачи добавляют
2 под одним замком через короткий
блок-лямбду. Напечатайте итог после
завершения всех.