Java的ReadWriteLock实现机制解析(1)

来源:互联网 发布:表格不同行数据相加 编辑:程序博客网 时间:2024/06/05 19:21
如果接触过多线程编程或者大规模并发应用的开发的人都应该知道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代码 复制代码 收藏代码
  1. public interface ReadWriteLock {   
  2.   /** get the readLock **/  
  3.   Sync readLock();   
  4.   
  5.   /** get the writeLock **/  
  6.   Sync writeLock();   
  7. }  
 

   ReadWriteLock的接口定义和后来JDK的实现基本一致。readLock和writeLock都实现Sync接口,这个接口两个主要的方法是acquire和realse,在以后的JDK中,变成了Lock的lock方法和unlock方法。


1.2 WriterPreferenceReadWriteLock类

   这个类包含了WriterLock类型的writerLock_和ReaderLock类型的readerLock_两个成员,而这两个类型又分别为WriterPreferenceReadWriteLock的内部类,这样做的一个考虑可能是为了能够让这两个类能够访问WriterPreferenceReadWriteLock的成员以及互相访问。

  先看看WriterPreferenceReadWriteLock中ReaderLock的实现

 

  该类的几个成员以及解释如下

 

Java代码 复制代码 收藏代码
  1. /*用来给Writer判断是否可以拿到write控制权*/  
  2. protected long activeReaders_ = 0;   
  3. /*当前writer线程*/  
  4. protected Thread activeWriter_ = null;   
  5. /*可以用来作为策略调整,此版本中没有太多作用*/  
  6. protected long waitingReaders_ = 0;   
  7. /*等待中的写,用来给Reader判断是否还有Writer在等待,以便实现Writer优先*/  
  8. protected long waitingWriters_ = 0;   
  9.   
  10. /*实际的ReaderLock*/  
  11. protected final ReaderLock readerLock_ = new ReaderLock();   
  12. /*实际的WriterLock*/  
  13. protected final WriterLock writerLock_ = new WriterLock();  
 

 

 先来看看 ReaderLock,它的两个主要方法acquire和release

  其中acquire的代码如下

 

Java代码 复制代码 收藏代码
  1. public void acquire() throws InterruptedException {   
  2.     if (Thread.interrupted())   
  3.         throw new InterruptedException();   
  4.     InterruptedException ie = null;   
  5.     synchronized (this) {   
  6.         /**  
  7.          * 判断是否能够获得读权  
  8.          */  
  9.         if (!startReadFromNewReader()) {   
  10.             for (;;) {   
  11.                 try {   
  12.                     /**  
  13.                      * 等待notify  
  14.                      */  
  15.                     ReaderLock.this.wait();   
  16.                     /**  
  17.                      * 再次判断能否获得读权  
  18.                      * 因为此处是Writer优先,当一个writer释放时, 
  19.                      * reader还必须等待其他wait的writer获得控制权并释放后才能获得控制权 
  20.                      */  
  21.                     if (startReadFromWaitingReader())   
  22.                         return;   
  23.                 } catch (InterruptedException ex) {   
  24.                     cancelledWaitingReader();   
  25.                     ie = ex;   
  26.                     break;   
  27.                 }   
  28.             }   
  29.         }   
  30.     }   
  31.     if (ie != null) {   
  32.         // fall through outside synch on interrupt.  
  33.         // This notification is not really needed here,  
  34.         // but may be in plausible subclasses  
  35.         writerLock_.signalWaiters();   
  36.         throw ie;   
  37.     }   
  38. }  

 

   acquire调用startReadFromNewReader,startReadFromWaitingReader,以及allowReader方法,这三个方法都属于WriterPreferenceReadWriteLock类

 

 

Java代码 复制代码 收藏代码
  1. protected synchronized boolean startReadFromNewReader() {   
  2.     boolean pass = startRead();   
  3.     if (!pass)   
  4.         ++waitingReaders_;   
  5.     return pass;   
  6. }   
  7.   
  8.   
  9. protected synchronized boolean startReadFromWaitingReader() {   
  10.     boolean pass = startRead();   
  11.     if (pass)   
  12.         --waitingReaders_;   
  13.     return pass;   
  14. }   
  15.   
  16.   
  17.   
  18. protected boolean allowReader() {   
  19.     //通过是否有正有控制权的activeWriter_和等待中的waitingWriters_来判断是Reader是否能获得控制权  
  20.     return activeWriter_ == null && waitingWriters_ == 0;   
  21. }   
  22.   
  23.   
  24. protected synchronized boolean startRead() {   
  25.     boolean allowRead = allowReader();   
  26.     if (allowRead)   
  27.         ++activeReaders_;   
  28.     return allowRead;   
  29. }  

 

     另外release的代码如下

 

Java代码 复制代码 收藏代码
  1. public void release() {   
  2.     Signaller s = endRead();   
  3.     if (s != null)   
  4.         s.signalWaiters();   
  5. }   
  6.   
  7.   
  8. protected synchronized Signaller endRead() {   
  9.     //只有当没有Reader在控制以及有等待的Writer的时候才返回   
  10.     //因为Reader之间没有互斥,所以返回writerLock   
  11.     if (--activeReaders_ == 0 && waitingWriters_ > 0)   
  12.         return writerLock_;   
  13.     else  
  14.         return null;   
  15. }  

     这里要注意的是endRead返回的是writerLock,这样他就可以完成notify和它互斥的writer

 

 

   下面看一下WriterLock的实现,同样也是acquire和release方法

   先看acquire

 

Java代码 复制代码 收藏代码
  1. public void acquire() throws InterruptedException {   
  2.     if (Thread.interrupted())   
  3.         throw new InterruptedException();   
  4.     InterruptedException ie = null;   
  5.     synchronized (this) {   
  6.         //试图获得writer权   
  7.         if (!startWriteFromNewWriter()) {   
  8.             for (;;) {   
  9.                 try {   
  10.   
  11.                     WriterLock.this.wait();    
  12.                     /**  
  13.                      * 重新判断是否能获得控制权  
  14.                      * 这时如果是writerLock的notify的话,理论上只有一个reader或者writer能够结束等待 
  15.                      * 如果是readerLock的notify的话,因为调用的是notifyAll,所以就必须重新竞争控制权 
  16.                      */  
  17.                     if (startWriteFromWaitingWriter())   
  18.                         return;   
  19.                 } catch (InterruptedException ex) {   
  20.                     cancelledWaitingWriter();   
  21.                     WriterLock.this.notify();   
  22.                     ie = ex;   
  23.                     break;   
  24.                 }   
  25.             }   
  26.         }   
  27.     }   
  28.     if (ie != null) {   
  29.         // Fall through outside synch on interrupt.  
  30.         // On exception, we may need to signal readers.  
  31.         // It is not worth checking here whether it is strictly  
  32.         // necessary.   
  33.         readerLock_.signalWaiters();   
  34.         throw ie;   
  35.     }   
  36. }  

 

   再看acquire调用的startWriteFromNewWriter,startWriteFromWaitingWriter和startWrite

 

Java代码 复制代码 收藏代码
  1. protected synchronized boolean startWriteFromNewWriter() {   
  2.     boolean pass = startWrite();   
  3.     //如果不能获得控制权,则等待数+1   
  4.     if (!pass)   
  5.         ++waitingWriters_;   
  6.     return pass;   
  7. }   
  8.   
  9.   
  10. protected synchronized boolean startWrite() {   
  11.   
  12.     // The allowWrite expression cannot be modified without  
  13.     // also changing startWrite, so is hard-wired  
  14.     //是否能获得写控制取决与是否已经有人有控制权(包括读和写)   
  15.     boolean allowWrite = (activeWriter_ == null && activeReaders_ == 0);   
  16.     if (allowWrite)   
  17.         activeWriter_ = Thread.currentThread();   
  18.     return allowWrite;   
  19. }   
  20.   
  21.   
  22. protected synchronized boolean startWriteFromWaitingWriter() {   
  23.     boolean pass = startWrite();   
  24.     //如果能获得控制权,则等待数-1   
  25.     if (pass)   
  26.         --waitingWriters_;   
  27.     return pass;   
  28. }  

 

    再来看看WriterLock的release实现

 

Java代码 复制代码 收藏代码
  1. public void release() {   
  2.     Signaller s = endWrite();   
  3.     if (s != null)   
  4.         //如果没有write的waiter,返回的的是readerLock_,则通知所有waiting的reader结束等待  
  5.         //如果有write的waiter,返回的的是writeLock,则通知一个正在等待的writer获得控制权  
  6.         s.signalWaiters();   
  7. }   
  8.   
  9.   
  10. protected synchronized Signaller endWrite() {   
  11.     activeWriter_ = null;   
  12.     //如果没有writer,则通知所有的等待的reader   
  13.     if (waitingReaders_ > 0 && allowReader())   
  14.         return readerLock_;   
  15.     //优先通知一个等待的writer   
  16.     else if (waitingWriters_ > 0)   
  17.         return writerLock_;   
  18.     else  
  19.         return null;   
  20. }  
 

    最后看看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

 

      同时附件里有Doug Lea - Concurrent Programming in Java Design Principles and Pattern,在这本书的3.3.3.1有关于Reader和Writer的一些设计模式讲解。

    Doug_Lea_-_Concurrent_Programming_in_Java_Design_Principles_and_Pattern_-_Addison_Wesley.pdf (2.4 MB)

 

 
原创粉丝点击