Java的ReadWriteLock实现机制解析(2)
1.3 EDU.oswego.cs.dl.util.concurrent.ReentrantWriterPreferenceReadWriteLock
????? 上一篇说到了WriterPreferenceReadWriteLock,这一篇说一下ReentrantWriterPreferenceReadWriteLock。??
????? 顾名思义,该类实现的是可重入的的WriterPreferenceReadWriteLock。允许readers和writers在各自线程里反复获得读或写的锁。这种方法主要用在
????? 该类是WriterPreferenceReadWriteLock的子类,与父类大体流程一致,但是startWrite,startRead ,allowReader ,endRead和endWrite被重写,下面逐一解释。 ?
??? 先看看新添加的成员变量
?
?
/**在activeWriter线程里,有多少次write锁的控制权被获取**/protected long writeHolds_ = 0; /**存放的每个reader线程共申请获得多少次读控制,key值是thread对象,value是次数**/protected HashMap readers_ = new HashMap();/*一个int的常量缓存*/protected static final Integer IONE = new Integer(1);
?
?? 再来看看Reader部分的重写函数
?
protected boolean allowReader() { //与父类的变化在于,activeWriter_ == Thread.currentThread(), //也就是说当本线程已经获得写控制的时候,返回true return (activeWriter_ == null && waitingWriters_ == 0) || activeWriter_ == Thread.currentThread();}protected synchronized boolean startRead() { Thread t = Thread.currentThread(); //查看本线程是否已经获得读控制 Object c = readers_.get(t); if (c != null) { // already held -- just increment hold count //计数+1 readers_.put(t, new Integer(((Integer)(c)).intValue()+1)); ++activeReaders_; return true; } //调用allowReader else if (allowReader()) { //将本线程获锁次数纪录在readers_这个map里 readers_.put(t, IONE); ++activeReaders_; return true; } else return false;}protected synchronized Signaller endRead() { Thread t = Thread.currentThread(); Object c = readers_.get(t); if (c == null) throw new IllegalStateException(); --activeReaders_; if (c != IONE) { // 多于一个读线程有控制权,more than one hold; 计数递减 int h = ((Integer)(c)).intValue()-1; Integer ih = (h == 1)? IONE : new Integer(h); readers_.put(t, ih); return null; } else { readers_.remove(t); if (writeHolds_ > 0) // 本线程还有写锁在占用控制权 return null; //其余与父类实现一样 else if (activeReaders_ == 0 && waitingWriters_ > 0) return writerLock_; else return null; }}
?
??? Reader部分相对于父类的变化在于
??? * 每个reader试图竞争控制权时,都会将本线程句柄与activeWriter进行比较,相同则认为是可以重入。
??? * 每个reader线程都在readers_的map里有一个计数器,判断当前有多少次获得reader锁权,释放的时候,只有当计数器为0时才通知其他写线程结束wait。
?
??
? 接着看看Writer部分的重写函数
?
protected synchronized boolean startWrite() { if (activeWriter_ == Thread.currentThread()) { // 反复重入 ++writeHolds_; return true; } else if (writeHolds_ == 0) { //如果没有人在读(activeReaders_==0)和,或者在读的线程和本线程一样,并且readers里没有其他线程 if (activeReaders_ == 0 || (readers_.size() == 1 && readers_.get(Thread.currentThread()) != null)) { //如果本线程在读中,则也可以进入writeLock activeWriter_ = Thread.currentThread(); writeHolds_ = 1; return true; } else return false; } else return false;}protected synchronized Signaller endWrite() { --writeHolds_; if (writeHolds_ > 0) //这是主要与父类不一样的地方,写锁计数标示仍然有写锁没有被释放 return null; else { //与父类一致 activeWriter_ = null; if (waitingReaders_ > 0 && allowReader()) return readerLock_; else if (waitingWriters_ > 0) return writerLock_; else return null; }}
?
?? Writer主要与父类不同的地方是
?? * 通过writeHolds来记录本线程获得锁的次数,以便在release时正确调用通知机制
?? * 通过当前线程和activeWriter线程比较来实现重入
?
1.3 EDU.oswego.cs.dl.util.concurrent.ReaderPreferenceReadWriteLock
?
? ReaderPreferenceReadWriteLock类和父类唯一不同就是allowReader方法
protected boolean allowReader() { //只要没有写,就允许读 return activeWriter_ == null;}
?? 这个类在大多数场景下都不太实用,多数人主要还是使用writer优先锁。