如何在Map <string,list =“”>?</string,>中处理对List的同步访问

时间:2010-11-08 22:17:37

标签: java collections concurrency groovy synchronization

3 个答案:

答案 0 :(得分:3)

您可能需要查看同步(集合)的工作方式:

这(作为非排他性示例)不是线程安全的:

if (users.get(userA).size() > 1) {
    users.get(userA).remove(0)

请记住,只有个人“synchronized”方法在没有更大锁定范围的情况下才能保证原子性。

快乐的编码。

编辑 - 按用户同步锁定(已更新以供评论):

通过使用标准数据结构,您可以使用ConcurrentHashMap实现每个键锁定 - 特别是使用'putIfAbsent'方法。 (这与明显不同比仅使用'同步HashMap'的get / put,见上文。)

下面是一些伪代码和注释:

public boolean add(long userA, long userB, String action) {
    // The put-if-absent ensures the *the same* object but may be violated when:
    //   -users is re-assigned
    //   -following approach is violated
    // A new list is created if needed and the current list is returned if
    // it already exists (as per the method name).
    // Since we have synchronized manually here, these lists
    // themselves do not need to be synchronized, provided:
    // Access should consistently be protected across the "higher"
    // structure (per user-entry in the map) when using this approach.
    List listA = users.putIfAbsent(userA, new List)
    List listB = users.putIfAbsent(userB, new List)
    // The locks must be ordered consistently so that
    // a A B/B A deadlock does not occur.
    Object lock1, lock2
    if (userA < userB) {
        lock1 = listA, lock2 = listB
    } else {
        lock1 = listB, lock2 = listA
    }
    synchronized (lock1) { synchronized (lock2) {{ // start locks

    // The rest of the code can be simplified, since the
    // list items are already *guaranteed* to exist there is no
    // need to alternate between add and creating a new list.
    bool eitherUserBusy = listA.length > 0 || listB.length > 0
    listA.add(action)
    listB.add(action)
    // make sure messages allows thread-safe access as well
    messages.put(action, [userA, userB])
    return !eitherUserBusy

    }} // end locks
}

在您的使用场景下,我没有关于单个常见锁定对象的展示方式。除非有明显的优势,否则通常建议采用“更简单”。

HTH和Happy编码。

答案 1 :(得分:2)

答案 2 :(得分:1)

在类中有两个全局状态持有者,并且在两个方法中的每个方法中都有复合操作来修改它们。因此,即使我们将Map的ConcurrentHashMap和List更改为CopyOnWriteArrayList之类的东西,它仍然不能保证一致的状态。

我看到你经常会写入List,所以,CopyOnWriteArrayList反正可能太贵了。 ConcurrentHashMap只有16路条带。如果你有更好的硬件,另一种选择是Cliff Click的highscalelib(在方法中适当锁定之后)。

回到一致性问题,如何使用ReentrantLock而不是同步,看看是否可以从lock() - to-unlock()序列中排除一些语句。如果您使用ConcurrentMap,add()中包含KeyK的前两个语句可以是乐观的,您可以将它们从锁定块中排除。

你真的需要消息地图吗?它有点像用户的反向索引。另一个选项是使用另一个watch()方法,在更改用户后,根据add()中的信号定期更新消息映射。或者,刷新可以完全是异步的。在这样做时,您可以在更新消息时对用户使用ReadWockLock和readLock()。在这种情况下,add()可以安全地获取用户的writeLock()。要使这个合理正确,还有一些工作要做。