Java的ReadWriteLock实现机制解析(一)
来源:互联网 发布:小猪cms收银系统 编辑:程序博客网 时间:2024/05/22 13:15
原文地址:http://developer.51cto.com/art/201103/249288.htm
如果接触过多线程编程或者大规模并发应用的开发的人都应该知道Readers-writer lock的设计模式,从英文字面上看就是对于资源允许多个Reader(复数)并发读,单个Writer写的锁机制,而Reader和Writer互斥。
现在的JDK里有一个ReadWriteLock的接口和一个ReentrantReadWriteLock的实现类,而其作者是赫赫有名的Doug Lea大牛(他有本 Concurrent Programming in Java Design Principles and Pattern ,推荐一下) 。早在JDK 1.4的时代,他就发表了自己的cocurrent包实现,其中就有多个ReadWriteLock的实现。下面会先聊一下早期Doug Lea在EDU.oswego.cs.dl.util.concurrent版本中对ReadWriteLock的实现,最后再说JDK版本的。
1.EDU.oswego.cs.dl.util.concurrent的实现
Doug Lea的这个版本:EDU.oswego.cs.dl.util.concurrent包中ReadWriteLock所包含的内容比JDK要丰富不少,除了ReentrantReadWriteLock还有若干个其他实现。先看一下ReadWriteLock在其中的类继承关系。源代码下载
这其中包含了4个ReadWriteLock,包括先进先出的FIFOReadWriteLock ,Writer优先的WriterPreferenceReadWriteLock ,Reader优先的ReaderPreferenceReadWriteLock ,可重入ReentrantWriterPreferenceReadWriteLock 。
1.1 EDU.oswego.cs.dl.util.concurrent.ReadWriteLock接口
Java代码
public interface ReadWriteLock { /** get the readLock **/ Sync readLock(); /** get the writeLock **/ Sync writeLock(); }
ReadWriteLock的接口定义和后来JDK的实现基本一致。readLock和writeLock都实现Sync接口,这个接口两个主要的方法是acquire和realse,在以后的JDK中,变成了Lock的lock方法和unlock方法。
1.2 WriterPreferenceReadWriteLock类
这个类包含了WriterLock类型的writerLock_和ReaderLock类型的readerLock_两个成员,而这两个类型又分别为WriterPreferenceReadWriteLock的内部类,这样做的一个考虑可能是为了能够让这两个类能够访问WriterPreferenceReadWriteLock的成员以及互相访问。
先看看WriterPreferenceReadWriteLock中ReaderLock的实现
该类的几个成员以及解释如下
Java代码
/*用来给Writer判断是否可以拿到write控制权*/ protected long activeReaders_ = 0; /*当前writer线程*/ protected Thread activeWriter_ = null; /*可以用来作为策略调整,此版本中没有太多作用*/ protected long waitingReaders_ = 0; /*等待中的写,用来给Reader判断是否还有Writer在等待,以便实现Writer优先*/ protected long waitingWriters_ = 0; /*实际的ReaderLock*/ protected final ReaderLock readerLock_ = new ReaderLock(); /*实际的WriterLock*/ protected final WriterLock writerLock_ = new WriterLock();
先来看看 ReaderLock,它的两个主要方法acquire和release
其中acquire的代码如下
Java代码
public void acquire() throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); InterruptedException ie = null; synchronized (this) { /** * 判断是否能够获得读权 */ if (!startReadFromNewReader()) { for (;;) { try { /** * 等待notify */ ReaderLock.this.wait(); /** * 再次判断能否获得读权 * 因为此处是Writer优先,当一个writer释放时, * reader还必须等待其他wait的writer获得控制权并释放后才能获得控制权 */ if (startReadFromWaitingReader()) return; } catch (InterruptedException ex) { cancelledWaitingReader(); ie = ex; break; } } } } if (ie != null) { // fall through outside synch on interrupt. // This notification is not really needed here, // but may be in plausible subclasses writerLock_.signalWaiters(); throw ie; } }
acquire调用startReadFromNewReader,startReadFromWaitingReader,以及allowReader方法,这三个方法都属于WriterPreferenceReadWriteLock类
Java代码
protected synchronized boolean startReadFromNewReader() { boolean pass = startRead(); if (!pass) ++waitingReaders_; return pass; } protected synchronized boolean startReadFromWaitingReader() { boolean pass = startRead(); if (pass) --waitingReaders_; return pass; } protected boolean allowReader() { //通过是否有正有控制权的activeWriter_和等待中的waitingWriters_来判断是Reader是 否能获得控制权 return activeWriter_ == null && waitingWriters_ == 0; } protected synchronized boolean startRead() { boolean allowRead = allowReader(); if (allowRead) ++activeReaders_; return allowRead; }
另外release的代码如下
Java代码
public void release() { Signaller s = endRead(); if (s != null) s.signalWaiters(); } protected synchronized Signaller endRead() { //只有当没有Reader在控制以及有等待的Writer的时候才返回 //因为Reader之间没有互斥,所以返回writerLock if (--activeReaders_ == 0 && waitingWriters_ > 0) return writerLock_; else return null; }
这里要注意的是endRead返回的是writerLock,这样它就可以完成notify和它互斥的writer
下面看一下WriterLock的实现,同样也是acquire和release方法
先看acquire
Java代码
public void acquire() throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); InterruptedException ie = null; synchronized (this) { //试图获得writer权 if (!startWriteFromNewWriter()) { for (;;) { try { WriterLock.this.wait(); /** * 重新判断是否能获得控制权 * 这时如果是writerLock的notify的话,理论上只有一个reader或者writer能够结束等待 * 如果是readerLock的notify的话,因为调用的是notifyAll,所以就必须重新竞争控制权 */ if (startWriteFromWaitingWriter()) return; } catch (InterruptedException ex) { cancelledWaitingWriter(); WriterLock.this.notify(); ie = ex; break; } } } } if (ie != null) { // Fall through outside synch on interrupt. // On exception, we may need to signal readers. // It is not worth checking here whether it is strictly // necessary. readerLock_.signalWaiters(); throw ie; } }
再看acquire调用的startWriteFromNewWriter,startWriteFromWaitingWriter和startWrite
Java代码
protected synchronized boolean startWriteFromNewWriter() { boolean pass = startWrite(); //如果不能获得控制权,则等待数+1 if (!pass) ++waitingWriters_; return pass; } protected synchronized boolean startWrite() { // The allowWrite expression cannot be modified without // also changing startWrite, so is hard-wired //是否能获得写控制取决与是否已经有人有控制权(包括读和写) boolean allowWrite = (activeWriter_ == null && activeReaders_ == 0); if (allowWrite) activeWriter_ = Thread.currentThread(); return allowWrite; } protected synchronized boolean startWriteFromWaitingWriter() { boolean pass = startWrite(); //如果能获得控制权,则等待数-1 if (pass) --waitingWriters_; return pass; }
再来看看WriterLock的release实现
Java代码
public void release() { Signaller s = endWrite(); if (s != null) //如果没有write的waiter,返回的的是readerLock_,则通知所有waiting的reader结束等待 //如果有write的waiter,返回的的是writeLock,则通知一个正在等待的writer获得控制权 s.signalWaiters(); } protected synchronized Signaller endWrite() { activeWriter_ = null; //如果没有writer,则通知所有的等待的reader if (waitingReaders_ > 0 && allowReader()) return readerLock_; //优先通知一个等待的writer else if (waitingWriters_ > 0) return writerLock_; else return null; }
最后看看WriterLock和ReaderLock如何实现Writer优先
* 首先在竞争控制权时,Reader在竞争控制权必须确认既没有占用控制权的Writer也没有等待控制权的writer
这里是调用的是allowRead方法
activeWriter_ == null && waitingWriters_ == 0;
* 其次在WriterLock的release方法里,调用endWrite,然后也会调用allowReader,确认没有等待的Writer才会返回readerLock_,并在signalWaiters里调用notifyAll通知所有的等待reader结束等待。而一旦有writer等待,则调用writerLock_,只通知等待的writer竞争控制权。具体代码见上文。
* 同时在ReaderLock的release方法里,调用endRead,返回writerLock_,通知等待的writer竞争控制权。具体代码见上文。
到此为止WriterPreferenceReadWriteLock的实现基本说完,这个版本的实现下载见http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html
Java的ReadWriteLock实现机制解析(二)
- Java的ReadWriteLock实现机制解析(一)
- Java的ReadWriteLock实现机制解析(1)
- Java的ReadWriteLock实现机制解析(2)
- Java的ReadWriteLock实现机制解析(二)
- java 自己实现 ReadWriteLock (一)
- Java多线程之~~~ReadWriteLock 读写分离的多线程实现
- Java多线程之~~~ReadWriteLock 读写分离的多线程实现
- java锁机制 - Lock ReadWriteLock Condition
- java反射机制的实现原理 (一)
- Java并发编程--深入理解ReadWriteLock锁机制
- Java中锁的应用之-ReadWriteLock
- Java中锁的应用之-ReadWriteLock
- java 线程 ReadWriteLock 读写锁的使用
- Asp.Net底层解析(一)——常规ASPX页面的实现机制
- java 多线之用ReadWriteLock实现 一个简单缓存
- C++实现的委托机制(一)
- Java线程总结(八):并发包------读写锁ReadWriteLock的简单例子详细理解
- java 锁对象Lock-同步问题更完美的处理方式(ReadWriteLock)
- 重复字符串
- 87. Scramble String
- 穿插套用
- ArcGIS读取gdb内要素
- 欢迎使用CSDN-markdown编辑器
- Java的ReadWriteLock实现机制解析(一)
- IDEA使用MyBatis 反向生成文件IOException
- class_copyPropertyList与class_copyIvarList的区别
- 重磅!三星召回全部国行Note 7 全额退款
- ThinkPHP每日值日功能,按星期筛选当天值日人
- 初探Linux下的时间函数 以及 NTP得到的值
- $.each()函数
- 乱谈
- HTML第二章上机练习3