`(DefaultDispatcher-worker-5 @coroutine#5) Subscri...
# coroutines
s
(DefaultDispatcher-worker-5 @coroutine#5) Subscribing 10000 listeners took 177ms
(DefaultDispatcher-worker-4 @coroutine#4) Subscribing 10000 listeners took 178ms
(DefaultDispatcher-worker-1 @coroutine#3) Subscribing 10000 listeners took 178ms
(DefaultDispatcher-worker-3 @coroutine#2) Subscribing 10000 listeners took 178ms
(DefaultDispatcher-worker-6 @coroutine#6) Subscribing 10000 listeners took 178ms
(main @coroutine#1) Unsubscribing all 49962 listeners took 0ms
u
Could it be due to extension functions being used on MutableMap/Collection instead of some concurrent implementations?
Check!
contains
is a kotlin extension on maps which inlines to
containsKey
And it is also a member on
ConcurrentHashMap
which calls ….
contanisValue
So your ConcurrentHashMap version is simply wrong 😉
could you check timing on both versions with
containsKey
instead of
contains
As a side note, this code races between multiple threads and is not protected by the guarantees of `ConcurrentHashMap`:
Copy code
while(observers.contains(uuid)) {
            Thread.sleep(1)
            uuid = UUID.randomUUID()
        }
You should probably use
putIfAbsent
Untested example:
Copy code
fun addListener(observer: Observer<T>): Subscription<T> {
        var uuid = UUID.randomUUID()
        while (observers.putIfAbsent(uuid, observer) != null) {
            Thread.sleep(1)
            uuid = UUID.randomUUID()
        }
        val subscription = Subscription(uuid, this)
        return subscription
    }
s
When I changed the contain to containKey, both MutableMap and ConcurrentHashMap performed the same, thank you. Also, your untested example worked just fine, I'm going with it, thank you! @uli
👍 2
u
Do you still need the
Thread.sleep(1)
? Or was that to avoid races?