ReentrantReadWriteLock - 一次许多读者,一次一个作家?
我对多线程环境有点陌生,我正在尝试针对以下情况提出最佳解决方案:
我每天早上从数据库读取一次数据,并将数据存储在 Singleton 对象的 HashMap 中。我有一个 setter 方法,仅当发生日内数据库更改时才会调用该方法(每天会发生 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();
}
}
I'm somewhat new to multithreaded environments and I'm trying to come up with the best solution for the following situation:
I read data from a database once daily in the morning, and stores the data in a HashMap in a Singleton object. I have a setter method that is called only when an intra-day DB change occurs (which will happen 0-2 times a day).
I also have a getter which returns an element in the map, and this method is called hundreds of times a day.
I'm worried about the case where the getter is called while I'm emptying and recreating the HashMap, thus trying to find an element in an empty/malformed list. If I make these methods synchronized, it prevents two readers from accessing the getter at the same time, which could be a performance bottleneck. I don't want to take too much of a performance hit since writes happen so infrequently. If I use a ReentrantReadWriteLock, will this force a queue on anyone calling the getter until the write lock is released? Does it allow multiple readers to access the getter at the same time? Will it enforce only one writer at a time?
Is coding this just a matter of...
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();
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
实现此目的的另一种方法(不使用锁)是写时复制模式。当您不经常写作时,它效果很好。这个想法是复制并替换字段本身。它可能如下所示:
这样,读者就完全并发了,他们付出的唯一代价是对 myStuff_ 的易失性读取(这是非常小的)。作者是同步的以确保相互排斥。
Another way to achieve this (without using locks) is the copy-on-write pattern. It works well when you do not write often. The idea is to copy and replace the field itself. It may look like the following:
With this, the readers are fully concurrent, and the only penalty they pay is a volatile read on myStuff_ (which is very little). The writers are synchronized to ensure mutual exclusion.
是的,如果写锁被一个线程持有,那么访问 getter 方法的其他线程将会阻塞,因为它们无法获取读锁。所以你在这里很好。有关更多详细信息,请阅读 ReentrantReadWriteLock 的 JavaDoc - http://download.oracle.com/javase/6/docs/api/java/util/concurrent/locks/ReentrantReadWriteLock.html
Yes, if the write lock is held by a thread then other threads accessing the getter method would block since they cannot acquire the read lock. So you are fine here. For more details please read the JavaDoc of ReentrantReadWriteLock - http://download.oracle.com/javase/6/docs/api/java/util/concurrent/locks/ReentrantReadWriteLock.html
你每天一开始就开始做这件事……你每天更新它 0-2 次,每天阅读它 100 次。假设读取需要花费 8 小时(28800 秒)内的 1 整秒(很长的时间),您的读取负载仍然很低。查看 ReentrantReadWriteLock 的文档,您可以“调整”模式,使其“公平”,这意味着等待时间最长的线程将获得锁。因此,如果您将其设置得公平,我认为您的写入线程不会被饿死。
参考文献
ReentrantReadWriteLock
You're kicking this thing off at the start of the day... you'll update it 0-2 times a day and you're reading it 100s of times per day. Assuming that the reading is going to take, say 1 full second(a looonnnng time) in an 8 hour day(28800 seconds) you've still got a very low read load. Looking at the docs for ReentrantReadWriteLock you can 'tweek' the mode so that it will be "fair", which means the thread that's been waiting the longest will get the lock. So if you set it to be fair, I don't think that your write thread(s) are going to be starved.
References
ReentrantReadWriteLock