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

原文地址: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实现机制解析(二)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值