繁体   English   中英

如何存储/访问数据并防止地图中的竞争条件,java

[英]How data is stored/accessed and preventing race conditions in maps, java

我们有这样一个案例。

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 中替换很多值。 我们需要 readAction 的一致性。 如果该方法以旧数据映射开始,则所有读取都应使用旧数据映射进行。

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
    }
}

这能确保一致性吗? 我相信克隆方法会在 memory 中分配一个不同的区域,并且会从那里发生新的引用。 是否会对性能产生任何影响? 而oldDataMap的memory用完后会放出来吗?

如果这是正确的方法,还有其他有效的方法可以实现吗?

我相信您的方法会奏效,因为updater()的所有更改都将发生在(深层)副本中,并且someAction()将不可见,直到在单个操作中更新了引用。

我理解您并不关心someAction()是否看到最新版本的地图内容,只要 map 是一致的,即在更新过程中没有观察到。 在这种情况下,您的someAction()无法查看不完整的 map。

请注意,最多 1 个线程应该能够调用updater() - 两个线程同时调用它意味着只有一个线程可以写入更新的 map。 我建议进行以下更改:

// no synchronization needed at this level, but volatile is important
private volatile HashMap<String,String> dataMap = new HashMap<>;

// if two threads attempt to call this at once, one blocks until the other finishes
public synchronized updater() {
    var writeDataMap = clone(dataMap);  // a deep copy

    // update writeDataMap - guaranteed no other thread updating
    // ... long operation

    dataMap = writeDataMap;             // switch visible map with the updated one 
}

public someAction() {
    var readDataMap = dataMap;

    // process readDataMap - guaranteed not to change while being read
    // ... long operation
}

这里的重要关键字是volatile ,以确保在updater()完成其工作后,其他线程可以访问更新的 map。 使用同步只是防止多个updater()线程相互干扰,并且主要是防御性的。

如果您想避免复制,您可以使用java.util.concurrent.locks.ReentrantReadWriteLock来保护对 map 的访问。 updater中使用写锁,在someAction中使用读锁。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM