写锁是一个独占锁,它使用了AQS中的state变量的低16位表示写锁的占有状态。如果有线程获取了读锁和写锁,再有线程申请写锁,则该线程会被挂起。另外,写锁是可重入锁,再次进入,state低16位的值加一。


      首先,我们还是看写锁的lock函数,源码如下:

Java高并发系列之ReentrantReadWriteLock源码分析(二)_java

       我们还是继续进去看看源码:

Java高并发系列之ReentrantReadWriteLock源码分析(二)_java_02

       进入tryAcquire源码看看,这里tryAcquire是在内部的Sync类实现,源码如下:

Java高并发系列之ReentrantReadWriteLock源码分析(二)_java_03

     该tryAcquire函数处理顺序如下:

1、变量c获取当前state的值。如果c不为0,说明读锁或写锁被某线程获取。

2、如果w=0,说明写锁为0,而c不为0。此时说明已经有线程获取读锁,直接返回false。此时再来看看是不是当前线程持有写锁的,如果是,还可以申请写锁(此时就是可重入了)。

3、如果上面情况都不满足,则进到setState函数,设置可重入次数。

4、如果c为0,说明没有线程拿到读锁和写锁,就进入最后这个if里面。来看看writeShouldBlock方法,这个方法分为公平和非公平。

      公平方式源码如下,还是去看AQS的阻塞队列是否有线程,有则返回true。

Java高并发系列之ReentrantReadWriteLock源码分析(二)_java_04

   非公平方式源码如下,直接返回false。

Java高并发系列之ReentrantReadWriteLock源码分析(二)_java_05

5、如果if里面的条件没满足,则进到最后setExclusiveOwnerThread来设置写锁的持有线程为当前线程。

6、如果之前tryAcquire函数返回false,则将当前线程放到AQS阻塞队列挂起。


下面来看看写锁的unlock源码。

Java高并发系列之ReentrantReadWriteLock源码分析(二)_java_06

        继续跟进去看看release源码,源码如下:

Java高并发系列之ReentrantReadWriteLock源码分析(二)_java_07

       这里还是看tryRelease源码,这个函数在AQS时抽象方法,这里再Sync类中实现的。下面我们来看看源码:

Java高并发系列之ReentrantReadWriteLock源码分析(二)_java_08

       这个tryRelease的处理逻辑很简单分为以下几个步骤:

1、首先调用isHeldExclusively看看是不是写锁的线程调用unlock方法,如果不是就抛异常。

2、如果是写锁的线程调用unlock方法,那么就计算nextc的值,也就是减一。

3、判断写锁的值是不是为0,如果是0,那么free就是true。则设置写锁的持有线程为null。最后设置state值,返回。