【发布时间】:2020-10-11 17:36:57
【问题描述】:
我正在尝试在定期清除的 hashmap 上支持并发。我有一个缓存可以存储一段时间的数据。每 5 分钟后,此缓存中的数据会发送到服务器。刷新后,我想清除缓存。问题是当我刷新时,数据可能会被写入此映射,而我正在使用现有密钥执行此操作。我将如何使这个进程线程安全?
data class A(val a: AtomicLong, val b: AtomicLong) {
fun changeA() {
a.incrementAndGet()
}
}
class Flusher {
private val cache: Map<String, A> = ConcurrentHashMap()
private val lock = Any()
fun retrieveA(key: String){
synchronized(lock) {
return cache.getOrPut(key) { A(key, 1) }
}
}
fun flush() {
synchronized(lock) {
// send data to network request
cache.clear()
}
}
}
// Existence of multiple classes like CacheChanger
class CacheChanger{
fun incrementData(){
flusher.retrieveA("x").changeA()
}
}
我担心上面的缓存没有正确同步。有没有更好/正确的方法来锁定这个缓存,这样我就不会丢失数据?我应该创建缓存的深层副本并清除它吗?
既然上面的数据可能会被另一个changer修改,那会不会导致问题?
【问题讨论】:
-
除了retrieve和flush之外,还有其他修改地图的功能吗?这两个函数都是在同一个锁上同步的,你怕什么问题?
-
另外,如果你的所有访问都是同步的,为什么还要使用 ConcurrentHashMap?
-
ConcurrentHashMap本身是线程安全的。扩展方法getOrPut似乎也是线程安全的(基于文档)。如果没有任何其他方法以非线程安全的方式修改映射 - 您可以摆脱这个锁。 -
问题是A类的值可以改变。如果 A 类的值发生更改并且我将其清除怎么办。我将更新示例。
-
@michalik OP 摆脱锁并不安全,因为刷新需要是原子的 - 需要读取然后清除整个映射,并且不能与此过程交错写入。
标签: java kotlin concurrency java.util.concurrent thread-synchronization