首页 > 解决方案 > java - Spring框架中Collection的可能竞态条件

问题描述

我正在使用tomcat下的spring框架编写可以处理多个并发请求的服务。在我的服务类中声明了一个静态变量,将在所有线程之间共享并受读写锁保护。这个静态集合被定期读取和写入。每次更新时,我都会获得写锁,当我读取它时,我会获得读锁。

存储在集合中的数据是来自数据库表的条目。所以它是一个List类型的集合。基本上我有一个很少更新的表,所以我将它缓存在进程内存中。

现在有时我需要记录这些数据,所以我可以在不获取方法中的锁的情况下记录返回对象。或者这会导致比赛条件吗?日志记录是为了调试。

另外,集合的返回值是只读的,不能被任何方法修改。服务对象之外的任何人都不会使用此集合。

我觉得这应该可行,因为当分配新集合时,旧集合只有在所有对它的引用都消失时才会消失。并且在更新写锁之前,不允许对旧对象或新对象的新引用。

代码如下所示:

class ObjService {
    
    private static Collection<OtherObj> _staticCollection;
    private static ReentrantReadWriteLock rwlock = new ReentrantReadWriteLock(true);
    
    private Collection<OtherObj> getCollection () {
       Collection<OtherObj> retVal = null;

       rwlock.readLock().lock();
       if (_staticCollection != null) {
         retVal = _staticCollection;
         rwlock.readLock().unlock();
         log (retVal);
       }
       else {
          rwlock.readLock().unlock();
          ReloadCollectionFromDB ();
          rwlock.readLock().lock();
          retVal = _staticCollection;
          rwlock.readLock().unlock();
       }
    }

    private ReloadCollectionFromDB  () {
      Collection<OtherObj> otherObjCol = null;

      try {
         otherObjCol = objRepo.findAll ();
      }
      catch (Exception ex) {
         // log exception
         return;
      }

      rwlock.writeLock().lock();
      _staticCollection = otherObjCol;
      rwlock.writeLock().unlock();
    }


    // periodically get data from DB
    @Scheduled(initialDelayString = "120000", fixedDelayString = "540000")
    void readLoadCache () {
       ReloadCollectionFromDB ();
    }
}

如果有更好的方法可以做到这一点,我将不胜感激。

非常感谢,~Ash

标签: javaspringmultithreadingrace-condition

解决方案


推荐阅读