0

让它变得简单:通常 update() 由多个线程执行。一旦这是真的 if(!isSplit && users.size() >= Constants.SPLIT_THRESHOLD) 我希望没有人在 split() 函数被单元格时执行 update() 方法。

public class Cell {
    private ConcurrentHashMap<Integer, User> users;
    private ConcurrentHashMap<Long, Cell> subCells;
    private boolean isSplit;
    private Lock splitLock;

    public Set<Integer> update(User user){

        //code executed by 1 thread
        if(!isSplit && users.size() >= Constants.SPLIT_THRESHOLD)
        {
            splitLock.lock();
            {
                try
            {
                    split();
                    isSplit = true;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                finally
                {
                    splitLock.unlock();
                }
            }
        }

        // code executed by multiple threads
        // on users hashmap
    }
    private void merge(){}
    private void split(){}
}
4

2 回答 2

4

在为写入/更新锁定时,一般模式是首先获取锁,然后检查您的条件(由写入/更新修改),然后写入。

lock
if(x) {
    write/update
}
unlock

与此进行对比,这类似于您发布的代码:

if(x) {
    lock
    write/update
    unlock
}

x 可以为线程 1 评估为真,同时线程 2 执行写入/更新导致 x 评估为假,但线程 1 已经在条件内,并且无论如何都会执行写入/更新。失败。

更新:响应更新的问题。

查看ReentrantReadWriteLock的 javadoc 。

您可能希望使用写锁(只有一个线程可以获取)隔离您的 split() 方法,并使用读锁(可以获取多个线程,只要没有人拥有写锁)来隔离更新方法的其余部分。

于 2013-08-29T14:57:40.713 回答
0

我无法告诉您您的代码当前是否获得了正确的锁定/同步。

但是,在正常情况下,我会使用原始对象互斥锁来完成以下操作:

private final Object splitLock = new Object();

// Use it like this ...
synchronized (splitLock) {
    split();
}

ReentrantLockAFAIK,使用原始对象互斥体没有性能优势。如果您要使用原始对象互斥锁不支持的功能,我只建议使用此类;

于 2013-08-29T15:04:28.407 回答