代码如下:
public ReentrantReadWriteLock getLock(String tableName) {
ReentrantReadWriteLock lock = locksMap.get(tableName);
if (lock == null) {
lock = new ReentrantReadWriteLock();
locksMap.put(tableName, lock);
}
}
//其中locksMap是一个带有键字符串(tableName)和值ReentrantReadWriteLock(Lock)的HashMap。
我的问题是,如果线程同时访问此方法,它们将获得具有相同“tableName”的不同Lock对象,因为Map的get和put方法是单独调用的。
任何有解释的解决方案都将受到赞赏? 提前谢谢。
答案 0 :(得分:3)
使用ConcurrentMap
通常会产生比synchronized
阻止更好的性能。
ConcurrentMap<String, ReadWriteLock> lockMap = new ConcurrentHashMap<>();
ReadWriteLock getLock(String key) {
ReadWriteLock lock = lockMap.get(key);
if (lock == null) {
lock = new ReentrantReadWriteLock();
ReadWriteLock other = lockMap.putIfAbsent(key, lock);
if (other != null) {
// another thread's putIfAbsent won
lock = other;
}
}
return lock;
}
ConcurrentMap<String, ReadWriteLock> lockMap = new ConcurrentHashMap<>();
ReadWriteLock getLock(String key) {
return lockMap.computeIfAbsent(key, ReentrantReadWriteLock::new);
}
首先,记录了ConcurrentHashMap
之类的实现,以便不对读取操作使用锁定。因此,在这种情况下,如果您打算获得单个密钥的锁定次数比您打算创建新锁定的次数多,那么这将减少线程争用。如果您使用synchronized
,即使已经创建了锁,您也会强制每个线程通过关键部分单个文件。
此外,实现可以执行更高级的锁定形式,甚至是 shard 锁定,这样两个编写器就不必相互阻塞(如果写入底层数据结构的不同分区)。同样,synchronized
使用单个监视器对象,无法从了解基础数据结构的详细信息中获益。
由于lambdas和函数引用,Java 8版本变成了单行。 ::new
语法引用相邻ReentrantReadWriteLock
类的public,no-arg构造函数。 computeIfAbsent
方法只会在必要时调用该构造函数,并且基本上所有的样板都可以在上面的Java 7版本中工作。如果创建新对象的成本昂贵或具有不幸的副作用,这尤其有用。请注意,Java 7版本具有以在某些情况下创建新的锁定实例,并且可能不会使用/返回新对象。
答案 1 :(得分:0)
通常,您将使用同步来完成此操作。最简单的形式是同步方法本身。
public synchronized ReentrantReadWriteLock getLock(String tableName) {
但是,如果您担心性能,我会考虑使用同步块的以下方法,但仅限于未找到初始锁定。
public ReentrantReadWriteLock getLock(String tableName) {
ReentrantReadWriteLock lock = locksMap.get(tableName);
if (lock != null) {
return lock;
}
synchronized(locksMap) {
lock = locksMap.get(tableName);
if (lock == null) {
lock = new ReentrantReadWriteLock();
locksMap.put(tableName, lock);
}
}
return lock;
}
答案 2 :(得分:0)
您可以将方法修改为synchronized
,也可以在方法中添加synchronization block,同时包含get()
和put()
来电。请注意,有一个伪模式(我更喜欢称之为习语),称为Double-checked Locking。
另一个选择是使用ConcurrentMap
,它提供putIfAbsent()
method。
请注意,您将讨论有关各种选项的性能的大量讨论/辩论。我鼓励你用健康的盐阅读它们。微优化和性能分析是危险的领域,代码的可读性和可维护性通常远远超过几微秒。