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;
}
}