比 while (reentrantLock.isLocked()) 等待更好的解决方案

Better solution than while (reentrantLock.isLocked()) for waiting

我有一个提供对地图的访问的服务 bean。有时我需要重建地图的内容,这需要几秒钟,我想在重建地图时阻止对地图的访问,因为它可以从不同的线程访问。

@Service
public class MyService {
  private Map<Key,Value> cache = null;
  private ReentrantLock reentrantLock = new ReentrantLock();

   public void rebuildCache(){
     try {
       reentrantLock.lock();
       cache = new ConcurrentHashMap<>();
       ... //processing time consuming stuff and building up the cache
       }finally {
        reentrantLock.unlock();
     }
   }
    
   public Value getValue(Key key){
     while (lock.isLocked()){}
     return cache.get(key);
   }
   ...
}

如你所见,我使用

while (reentrantLock.isLocked()){}

检查锁是否被锁定并等待解锁。这个解决方案似乎很脏。有更好的解决方案吗?

我会提议 ReadWriteLock。 有了它你可以想读多少次就读多少次,只要读锁没有被锁定。

@Service
public class MyService {
  private Map<Key,Value> cache = null;
  private ReentrantLock reentrantLock = new ReentrantLock();

   public void rebuildCache(){
     try {
       reentrantLock.writeLock().lock();
       cache = new ConcurrentHashMap<>();
       ... //processing time consuming stuff and building up the cache
       }finally {
        reentrantLock.writeLock().unlock();
     }
   }

   public Value getValue(Key key){
    if(reentrantLock.getReadLock().lock()){
     return cache.get(key);
    }finally{
       reentrantLock.getReadLock().unlock();
    }
   }
   ...
}

改用 ReentrantReadWriteLock

在你的写入方法中:

theLock.writeLock().lock();
try {
    // update the map
} finally {
    theLock.writeLock().unlock();

}

在读取方法中,改用.readLock()。

这个有问题,但是在更新地图的过程中,所有的阅读器都会被屏蔽;另一种解决方案是使用普通锁将旧地图的引用替换为更新后的新地图,并使用普通旧 synchronized.


但更重要的是,您对锁的使用不正确。你应该这样做:

theLock.lock();
try {
    // whatever
} finally {
    theLock.unlock();
}

想象一下如果您当前的锁锁定失败会发生什么:您将始终尝试解锁并最终得到 IllegalLockStateException