我的目标是同步对程序外部的多个(数千个)对象的访问。 ReentrantReadWriteLock
提供了一个很好的模型来控制单个对象。但是,在我的情况下,为每个同步的对象创建一个RWL对象是疯狂的。幸运的是,同时会访问少于百的人。
因此,我决定创建一个提供如下界面的服务:
void acquireReadLock(String id) {
rwl = ....... // get or create RWL object
rwl.writeLock().lock();
}
void acquireWriteLock(String id) {
}
void releaseReadLock(String id) {
}
void releaseWriteLock(String id) {
}
实施"获得"方法使用简单的延迟初始化来为项目实例化RWL对象,或从缓存中获取它。然而,"发布"方法应该包括额外的逻辑,检查是否仍然需要RWL(=没有锁)。如果没有,我可以安全地从缓存中删除RWL,否则内存很快会被它们淹没。
要实现此清理逻辑,我需要一种方法来执行相应的检查。方法' getReadLockCount()'和' isWriteLocked()'似乎是合适的候选人,但是来自JavaDoc的这个qoute让我很担心:
此方法旨在用于监视系统状态,而不是用于监视系统状态 同步控制。
那么,将它们用于我的任务是否安全?是否有其他解决方案?
答案 0 :(得分:1)
单独使用getReadLockCount()和isWriteLocked()对您的任务来说不安全,因为当释放线程调用函数时锁可能是空闲的,但是另一个线程可以在释放线程之前获取或开始等待锁从缓存中删除了锁。后一个异议 - 另一个线程可以开始等待锁定 - 也适用于tryLock()。
处理这种情况的一种方法是使用一个简单的对象作为保护锁,在锁定或解锁读/写锁时,需要由任何线程同步。任务完成后,它将锁定防护锁,然后如果读/写锁完全空闲,则移除读/写锁,然后移除防护锁。到那时可能还有其他线程等待保护锁,但是一旦获得它,他们就会看到不再有可用的读/写锁,并且它们返回并创建一个新的保护锁和读/写锁。
创建锁的过程需要以某种方式同步 - 全局使用synchronized
块或函数,或者可能使用ConcurrentHashMap
及其putIfAbsent()
方法 - 以避免尝试同时创建锁的两个线程之间的竞争条件。在尝试将锁定和新的读/写锁定放入缓存之前,线程应该锁定防护锁,如果它从putIfAbsent()
获得了不同的防护锁,则中止新的锁创建并等待对象而是返回。
就个人而言,因为这种方法有点复杂,并且如果写得不完整可能导致隐藏的竞争条件,我会考虑只保留所有外部对象的读/写锁。至少有百万个外部对象应该没有问题,如果你的进程有几千兆字节的可用内存,那就应该有数百或数亿个。