iseki
10/28/2023, 8:09 PMacquired > permits
?
I'm trying to write a test case, which require to wait some sub-coroutine running to a point.
So I'm trying:
kotlin
runBlocking{
val sem = Semaphore(1, 3)
repeat(3){
launch{ sem.release() }
}
sem.acquire()
}
Especially in Java it's easy to impl. Just java.util.concurrent.Semaphore(-3)
.Mikhail
10/29/2023, 8:56 AMiseki
10/29/2023, 2:38 PMSzymon Jeziorski
10/30/2023, 10:36 AMval semaphore = kotlinx.coroutines.sync.Semaphore(5)
You are sure that semaphore
object allows exactly 5 available permits, and whatever happens, this number will not change in runtime, and with this information you can use it for example to limit effective parallelism. And you can do it without worrying of its behavior changing due to alteration of total available permits (intentional or not).
Java's version of Semaphore does not guarantee any such contract, the number of total available permits can change in runtime fairly easily.
val semaphore = java.util.concurrent.Semaphore(3) // 3 initial permits available
semaphore.release() // 4 permits available
Looking at the above Java's example: initially created Semaphore has 3 available permits and 0 permits acquired. When we call release
line after, it would be perfectly logical to me, to actually release something, that something being already acquired permit. What actually happens is the internal counter of available permits being incremented, resulting in increase of the number of total available permits. For Kotlin's Semaphore, calling release
in such case would result in IllegalStateException
- there are no permits acquired, so it makes sense that there's nothing to release.
In the same way, it wouldn't be logical for Kotlin's Semaphore to held negative number of acquired permits, or have number of acquired permits larger than number of total permits.
Kotlin's version of Semaphore has its validations underneath, enforcing usage correct to its contract (which to me is a great thing), while Java however, has much looser approach and leaves it to user, to use the API correctly. Quoting part of java.util.concurrent.Semaphore.release
documentation for example:
There is no requirement that a thread that releases a permit must have acquired that permit by calling acquire. Correct usage of a semaphore is established by programming convention in the application.
With all that said, in your case I would just use different tools to achieve what you need (bigger context would be appreciated here, in case you need some help with it)