ReentrantReadWriteLock - 一次很多读者,一次一个作家?

时间:2011-05-12 18:24:37

标签: java multithreading synchronized reentrantreadwritelock

我对多线程环境有些新意,我正在尝试针对以下情况提出最佳解决方案:

我每天早上从数据库中读取一次数据,并将数据存储在Singleton对象的HashMap中。我有一个setter方法,只有在发生日内DB更改时才会调用(每天会发生0-2次)。

我还有一个getter,它在地图中返回一个元素,这个方法每天被调用数百次。

我担心在我清空和重新创建HashMap时调用getter的情况,因此试图在空/格式错误的列表中查找元素。如果我使这些方法同步,它会阻止两个读者同时访问getter,这可能是性能瓶颈。由于写入很少发生,我不想过多地受到性能影响。如果我使用ReentrantReadWriteLock,这会强制任何调用getter的队列,直到释放写锁定为止?是否允许多个读者同时访问getter?它一次只会强制执行一个作者吗?

编码只是......的问题。

private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
private final Lock read = readWriteLock.readLock();
private final Lock write = readWriteLock.writeLock();

public HashMap getter(String a) {
    read.lock();
    try {
        return myStuff_.get(a);            
    } finally {
        read.unlock();
    }
}

public void setter() 
{
    write.lock();
    try {
        myStuff_ = // my logic
     } finally {
          write.unlock();
    }
}

3 个答案:

答案 0 :(得分:14)

实现此目的的另一种方法(不使用锁)是写时复制模式。当你不经常写作时,它很有效。我们的想法是复制和替换字段本身。它可能如下所示:

private volatile Map<String,HashMap> myStuff_ = new HashMap<String,HashMap>();

public HashMap getter(String a) {
    return myStuff_.get(a);
}

public synchronized void setter() {
    // create a copy from the original
    Map<String,HashMap> copy = new HashMap<String,HashMap>(myStuff_);
    // populate the copy
    // replace copy with the original
    myStuff_ = copy;
}

有了这个,读者完全并发,他们支付的唯一惩罚是myStuff_上的易失性读取(这很少)。作者是同步的,以确保相互排斥。

答案 1 :(得分:2)

是的,如果一个线程持有写锁定,那么访问getter方法的其他线程将阻塞,因为它们无法获取读锁定。所以你在这里很好有关详细信息,请阅读ReentrantReadWriteLock的JavaDoc - http://download.oracle.com/javase/6/docs/api/java/util/concurrent/locks/ReentrantReadWriteLock.html

答案 2 :(得分:0)

你在一天开始时就把这件事搞砸了......你每天会更新它0-2次,你每天都要读100次。假设读数将在8小时(28800秒)内完成一秒钟(一个懒人时间),你的读取负荷仍然非常低。查看ReentrantReadWriteLock的文档,您可以“调整”模式以使其“公平”,这意味着等待时间最长的线程将获得锁定。因此,如果你认为它是公平的,我认为你的写作线程不会被饿死。

参考

ReentrantReadWriteLock