class ResourceLocker { private val lockedResourceContext = Executors .newSingleThreadExecutor() .asCoroutineDispatcher() private val lockedResources = mutableSetOf() suspend fun getLock(resId: Long, action: suspend () -> Unit) { // actually get lock withContext(lockedResourceContext) { suspendUntilLockAcquired(resId) } //locked, so nothing else can touch it. action() // release lock withContext(lockedResourceContext) { lockedResources.remove(resId) } } private tailrec suspend fun suspendUntilLockAcquired(resId: Long) { when (lockedResources.contains(resId)) { true -> lockedResources.add(resId) false -> { delay(25) suspendUntilLockAcquired(resId) } } } }