Leon K
02/21/2020, 2:18 PMsuspend
fun and a non-suspending function. I cannot just do @Synchronized
on the blocking one and use Mutex
on the suspend-one as these don't exclude each other, such that there is still the posibility of two concurrent accesses.
It seems as tough Mutex
is not usable from non-blocking code, and @Synchronized
doesn't help with `suspend fun`s.
what's the best approach here?diesieben07
02/21/2020, 2:44 PMMutex
inside runBlocking
to achieve an effect similar to @Synchronized
(block instead of suspend when waiting for the lock).Leon K
02/21/2020, 2:45 PMuli
02/21/2020, 2:47 PMLeon K
02/21/2020, 2:48 PMrunBlocking
to somehwere else...Zach Klippenstein (he/him) [MOD]
02/21/2020, 2:53 PMAtomicReference
and not deal with locking at all.Leon K
02/21/2020, 2:54 PMLeon K
02/21/2020, 2:57 PMAtomicReference
a suspend (T) -> T
? otherwise this would only solve my non-suspending case, which is only half my use-case ;DZach Klippenstein (he/him) [MOD]
02/21/2020, 2:59 PMArkadii Ivanov
02/21/2020, 3:01 PMsynchronized {}
block. Just don't suspend inside the block.Leon K
02/21/2020, 3:02 PMclass ExpirationBasedCache<V>(private val expirationTimeSeconds: Long) {
@Volatile
private var cacheData: Pair<Long, V>? = null
private val mutex = Mutex()
/** Read the value from the cache if it exists and is not expired,
* otherwise calculate a new value using the given [function][f]. */
fun getValueBy(f: suspend () -> V): V = runBlocking { getValueBySuspending(f) }
/** Read the value from the cache if it exists and is not expired,
* otherwise calculate a new value using the given [function][f]. */
suspend fun getValueBySuspending(f: suspend () -> V): V = mutex.withLock {
cacheData
?.takeIf { (timeOfCache, _) -> System.currentTimeMillis() - timeOfCache < expirationTimeSeconds * 1000 }
?.second
?: f().also { cacheData = Pair(System.currentTimeMillis(), it) }
}
}
because this cache should be accessible from both suspending and non-suspending contexts, I need to support both.
The idea is that, if one thread is currently calculating the value, others don't start doing the same thing but wait for the first thread and then reuse it's result.Leon K
02/21/2020, 3:09 PMsynchronized
is not an option as i DO need to suspend within the blockArkadii Ivanov
02/21/2020, 3:10 PMsupend fun get()
and fun getBlocking()
The last one will call the first under runBlocking block. And use Mutex.Leon K
02/21/2020, 3:11 PM