Java 检查ReentrantReadWriteLock的状态(已锁定读/写,线程正在等待)

Java 检查ReentrantReadWriteLock的状态(已锁定读/写,线程正在等待),java,multithreading,concurrency,locking,Java,Multithreading,Concurrency,Locking,我正在实现一个DocumentProvider,它必须支持对它提供的文档的并发访问。下面是它的大致工作原理: 文档按需加载 当文档被使用时,它被保存在activeDocuments(按文档id索引的Map)中 文档停止使用后,它将从activeDocuments移动到idleDocuments(也是按文档id索引的Map)idleDocuments是一个LRU缓存,这意味着在某个点上,此缓存中的文档可能会被丢弃 根据通常的读者/作者政策,可以访问每个文档进行阅读或写作。这是使用每个活动的文档实

我正在实现一个
DocumentProvider
,它必须支持对它提供的
文档的并发访问。下面是它的大致工作原理:

  • 文档按需加载
  • 当文档被使用时,它被保存在
    activeDocuments
    (按文档id索引的
    Map
    )中
  • 文档停止使用后,它将从
    activeDocuments
    移动到
    idleDocuments
    (也是按文档id索引的
    Map
    idleDocuments
    是一个LRU缓存,这意味着在某个点上,此缓存中的
    文档
    可能会被丢弃
  • 根据通常的读者/作者政策,可以访问每个文档进行阅读或写作。这是使用每个活动的
    文档实现的
  • 锁定文档的尝试是非锁定的:线程将调用
    tryLock
    而不是
    lock
    。如果它无法锁定文档,将抛出一个
    CannotLockException
    ,线程将不得不处理它——具体如何处理超出了这个问题的范围。(示例:显示消息“文档当前已锁定。是否打开只读副本?”)
下面是代码(稍微简化):

公共类文档管理器{
/**
*当前正在使用的文档(按文档ID索引)。
*始终在同步(activeDocuments)块中访问。 */ 私人地图文件; /** *已加载但未使用的文档(按索引) *documentId)。这是一个LRU缓存,如果 *缓存已满。
*始终在同步(activeDocuments)块中访问。 */ 私有地图闲置文档; /** *{@link#activeDocuments}的读/写锁定(索引为 *文档ID)。
*始终在同步(读写锁定)块中访问。 */ 私有地图读写库; 公共文档openDocument(字符串documentId,LockMode LockMode)引发CannotLockException{ 单据=空; 已同步(动态文档){ document=activeDocuments.get(documentId); if(document==null){ 文件=加载文件(文件ID); activeDocuments.put(documentId,document); } } 如果(文档!=null){ tryLock(documentId,lockMode); } 归还文件; } 受保护的文档loadDocument(字符串documentId){ 已同步(动态文档){ Document Document=idleDocuments.remove(documentId); if(document==null){ document=//从磁盘加载文档 } 归还文件; } } public void tryLock(字符串documentId,LockMode LockMode)引发CannotLockException{ 已同步(读写锁定){ ReentrantReadWriteLock readWriteLock=readWriteLock.get(documentId); if(readWriteLock==null){ readWriteLock=新的ReentrantReadWriteLock(); put(documentId,readWriteLock); } Lock Lock=getLock(读写锁,锁模式); 如果(!lock.tryLock()){ 抛出新的CannotLockException(“无法锁定文档”+documentId+”表示“+lockMode”); } } } public void unlock(字符串documentId)抛出CannotUnlockException{ REENTRANDREADWRITELOCK readWriteLock=null; 已同步(读写锁定){ readWriteLock=readWriteLock.get(documentId); if(readWriteLock==null){ 抛出新的CannotUnlockException(“无法解锁文档”+documentId +“:当前未锁定”); } Lock=null; //(1)从isWriteLocked的javadoc: //查询写锁是否由任何线程持有。此方法为 //设计用于监控系统状态,而不是 //同步控制。 if(readWriteLock.isWriteLocked()){ lock=readWriteLock.writeLock(); }否则{ lock=readWriteLock.readLock(); } 试一试{ lock.unlock(); }捕获(非法监视器状态异常e){ 抛出新的CannotUnlockException(“无法解锁文档”+documentId +“:此线程上没有任何锁”,e); } //(2)从hasQueuedThreads的javadoc: //查询是否有线程正在等待获取读或写操作 //写锁。请注意,因为取消操作可能随时发生 //但是,真正的返回并不保证任何其他线程都会返回 //获取锁。此方法主要用于 //监视系统状态。 如果(!readWriteLock.hasQueuedThreads())&& //(3)从getReadLockCount的javadoc: //查询此锁的读取锁数。此 //方法设计用于监视系统状态,而不是 //用于同步控制。 readWriteLock.getReadLockCount()=0){ 已同步(动态文档){ Document Document=activeDocuments.remove(documentId); idleDocuments.put(文档ID,文档); //从地图上移除锁以释放一些空间。 readWriteLocks.remove(文档ID); } } } } 受保护的锁getLock(可重入的写锁、锁模式锁模式){ 开关(锁定模式){ 案情如下: return lock.readLock(); 案例写作: return lock.readLock();
public enum LockMode {
   READ,
   WRITE;
}
public class DocumentManager {

    /**
     * Documents currently in use (indexed by documentId).<br>
     * Always accessed in a synchronized(activeDocuments) block.
     */
    private Map<String, Document> activeDocuments;

    /**
     * Documents that have been loaded but are not in use (indexed by
     * documentId). This is a LRU cache and documents may be discarded if the
     * cache is full.<br>
     * Always accessed in a synchronized(activeDocuments) block.
     */
    private Map<String, Document> idleDocuments;

    /**
     * Read/write locks in for the {@link #activeDocuments} (indexed by
     * documentId).<br>
     * Always accessed in a synchronized(readWriteLocks) block.
     */
    private Map<String, ReentrantReadWriteLock> readWriteLocks;

    public Document openDocument(String documentId, LockMode lockMode) throws CannotLockException {
        Document document = null;
        synchronized (activeDocuments) {
            document = activeDocuments.get(documentId);
            if (document == null) {
                document = loadDocument(documentId);
                activeDocuments.put(documentId, document);
            }
        }
        if (document != null) {
            tryLock(documentId, lockMode);
        }
        return document;
    }

    protected Document loadDocument(String documentId) {
        synchronized (activeDocuments) {
            Document document = idleDocuments.remove(documentId);
            if (document == null) {
                document = // load the document from disk
            }
            return document;
        }
    }

    public void tryLock(String documentId, LockMode lockMode) throws CannotLockException {
       synchronized (readWriteLocks) {
          ReentrantReadWriteLock readWriteLock = readWriteLocks.get(documentId);
          if (readWriteLock == null) {
             readWriteLock = new ReentrantReadWriteLock();
             readWriteLocks.put(documentId, readWriteLock);
          }
          Lock lock = getLock(readWriteLock, lockMode);
          if (!lock.tryLock()) {
              throw new CannotLockException("Cannot lock document " + documentId + " for " + lockMode);
          }
       }
    }

    public void unlock(String documentId) throws CannotUnlockException {
        ReentrantReadWriteLock readWriteLock = null;
        synchronized (readWriteLocks) {
            readWriteLock = readWriteLocks.get(documentId);

            if (readWriteLock == null) {
                throw new CannotUnlockException("Cannot unlock document " + documentId
                        + ": it is not currently locked");
            }

            Lock lock = null;
            // (1) From isWriteLocked's javadoc:
            // Queries if the write lock is held by any thread. This method is
            // designed for use in monitoring system state, not for
            // synchronization control.
            if (readWriteLock.isWriteLocked()) {
                lock = readWriteLock.writeLock();
            } else {
                lock = readWriteLock.readLock();
            }
            try {
                lock.unlock();
            } catch (IllegalMonitorStateException e) {
                throw new CannotUnlockException("Cannot unlock document " + documentId
                        + ": this thread does not own any lock on it", e);
            }

            // (2) From hasQueuedThreads's javadoc:
            // Queries whether any threads are waiting to acquire the read or
            // write lock. Note that because cancellations may occur at any
            // time, a true return does not guarantee that any other thread will
            // ever acquire a lock. This method is designed primarily for use in
            // monitoring of the system state.
            if (!readWriteLock.hasQueuedThreads() &&
                // (3) From getReadLockCount's javadoc:
                // Queries the number of read locks held for this lock. This
                // method is designed for use in monitoring system state, not
                // for synchronization control.
                readWriteLock.getReadLockCount() == 0) {
                synchronized (activeDocuments) {
                    Document document = activeDocuments.remove(documentId);
                    idleDocuments.put(documentId, document);
                    // Remove the lock from the map to free some space.
                    readWriteLocks.remove(documentId);
                }
            }
        }
    }

    protected Lock getLock(ReentrantReadWriteLock lock, LockMode lockMode) {
       switch (lockMode) {
       case READ:
          return lock.readLock();
       case WRITE:
          return lock.readLock();
       default:
          throw new IllegalArgumentException("Unknown " + LockMode.class.getName() + ": " + lockMode);
       }
    }

}
class MyReentrantReadWriteLock {
    private int state; // 0 - free, -1 - write locked, n>0 - read locked n times
    public bool tryLock(LockMode lockMode) {
        switch(lockMode) {
        case READ:
            if(state == -1) return false; // Already write-locked.
            state++;
            return true;
        case WRITE:
            if(state) return false; // Already locked.
            state = -1;
            return true;
        }
    public void unlock() {
         switch(state) {
         case 0:
             // error: not locked
         case -1:
             state = 0; // write unlock
             break;
         default:
             state--; // read unlock
         }
    }
    public bool isLocked() {
        return state != 0;
    }
};
// User of the document
{
    doc = documentManager.openDocument("doc1", WRITE);
    //...
    doSomethingWithDocument(doc);
    //...
    documentManager.closeDocument(doc);
}

// Implementation of auxiliary function
void doSomethingWithDocument(Document doc) {
     if(!doc.isWritable()) throw new Exception("Read-only document!");
     // Process document
}
void makeReadOnly(Document doc)
{
     synchronized(readWriteLocks)
     {
         doc->m_isWritable = false;
     }
}