我们有这样的案子。
class A{
class foo{
//Map with a lot of entries
private HashMap<String,String> dataMap;
public updater(){
// updates dataMap
// takes several milliseconds
}
public someAction(){
// needs to perform read on dataMap
// several times, in a long process
// which takes several milliseconds
}
}
问题是,someaction和updater都可以同时调用,someaction是一个更频繁的方法。如果调用updater,它可以替换datamap中的许多值。我们需要行动的一致性。如果该方法以old datamap开始,那么所有读取都应该以old datamap进行。
class foo{
//Map with a lot of entries
private HashMap<String,String> dataMap;
public updater(){
var updateDataMap = clone(dataMap); // some way to clone data from map
// updates updateDataMap instead of dataMap
// takes several milliseconds
this.dataMap = updateDataMap;
}
public someAction(){
var readDataMap = dataMap;
// reads from readDataMap instead of dataMap
// several times, in a long process
// which takes several milliseconds
}
}
这能确保一致性吗?我相信克隆方法将在内存中分配一个不同的区域,新的引用将从那里发生。是否会对绩效产生影响?olddatamap的内存在使用后会被释放吗?
如果这是正确的方法,有没有其他有效的方法来达到同样的效果?
2条答案
按热度按时间qacovj5a1#
我相信你的方法会奏效,因为
updater()
将出现在(深度)副本中,并且在someAction()
直到在单个操作中更新引用。我知道你不在乎
someAction()
查看Map内容的最新版本,只要Map是一致的,也就是说,它在更新过程中没有被观察到。在这种情况下,你没有办法someAction()
看一张不完整的Map。请注意,最多只能有一个线程能够调用
updater()
-两个线程同时调用它意味着其中只有一个线程可以编写更新的Map。我建议进行以下更改:这里的重要关键字是volatile,以确保其他线程可以在
updater()
完成任务。使用synchronized可以简单地防止多个updater()
线程之间相互干扰,并且大多是防御性的。fnvucqvd2#
如果你想避免复制,你可以使用
java.util.concurrent.locks.ReentrantReadWriteLock
以保护对Map的访问。使用中的写锁updater
读取锁定someAction
.