Coroutine synchronization
Kotlin provides a thread non-blocking features to synchronize coroutoines.
Mutex protects all modifications of the shared state with a critical section that is never executed concurrently. Mutex has two states: locked and unlocked. It is non-reentrant, that is invoking lock even from the same thread/coroutine that currently holds the lock still suspends the invoker.
Semaphore limits the number of coroutines that can execute specified code at the same time. Semaphore with permits = 1 is essentially a Mutex.
Mutex similar to the synchronize keyword and ReentrantLock class in Java. Semaphore is similar to the java.util.concurrent.Semaphore in Java.
Mutex usage example
// using a mutex will be faster than using the AtomicInteger class
val mutex = Mutex()
var counter = 0
fun main() = runBlocking {
withContext(Dispatchers.Default) {
massiveRun {
// protect each increment with lock
mutex.withLock {
counter++
}
}
}
println("Counter = $counter")
}
Semaphore usage example
val requestSemaphore = Semaphore(5)
val futures = mDownloadJobs.map {
async {
// Will limit number of concurrent requests to 5
requestSemaphore.withPermit {
it.loadData()
}
}
}
val responses = futures.awaitAll()
Sequential execution
// Sequential execution of incoming blocks
// which can be passed from different coroutines
class QueueExecutor {
private val mutex: Mutex = Mutex()
suspend fun <T> enqueue(block: suspend () -> T): T {
mutex.withLock {
return block()
}
}
}