Java并发之AQS与ReentrantReadWrite

书接上文

ReentrantReadWriteLock样例

public class ReadWriteLockTest {
    public DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss:SSS");
    public ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    public  String getTime(){
        return LocalDateTime.now(ZoneOffset.of("+8")).format(formatter);
        //字符串转时间String dateTimeStr = "2018-07-28 14:11:15";
    }
    public void readLockTest(){
        try {
               readWriteLock.readLock().lock();
               System.out.println("start readLockTest at "+getTime());
               Thread.sleep(2000);
               System.err.println("end readLockTest at "+getTime());
        }catch (InterruptedException e){
            e.printStackTrace();
        }finally {
            readWriteLock.readLock().unlock();
        }
    }
    public void writeLockTest(){
        try {
            readWriteLock.writeLock().lock();
            System.out.println("start writeLockTest at "+getTime());
            Thread.sleep(2000);
            System.err.println("end writeLockTest at "+getTime());
        }catch (InterruptedException e){
            e.printStackTrace();
        }finally {
            readWriteLock.writeLock().unlock();
        }
    }

    public static void main(String[] args) {
       /*
        a << b就表示把a转为二进制后左移b位(在后面添b个0)。
        a >> b表示二进制右移b位(去掉末b位).
       */
        ReadWriteLockTest readWriteLockTest = new ReadWriteLockTest();
        IntStream.range(0,4).forEach(i-> new Thread(readWriteLockTest::readLockTest).start());
        IntStream.range(0,4).forEach(i-> new Thread(readWriteLockTest::writeLockTest).start());
    }
}
复制代码

image.png

不厌其烦的阅读jdk源码

ReadWriteLock接口

image.png

其中一个实现类ReentrantReadWriteLock

构造方法和成员变量

image.png

image.png

WriteLock的构造类似,不再赘述

AQS在ReentrantReadWriteLock中的角色

image.png

ReentrantReadWriteLock的ReadLock获取锁的源码分析

image.png

ReentrantReadWriteLock的WriteLock获取锁的源码分析

image.png

Sync有两个版本

image.png

***ShouldBlock(),在获取锁的tryAcquire()方法中有调用

小结——关于ReentrantReadWriteLock获取锁的操作逻辑:

  • 读锁:
    • 在获取读锁时,会尝试判断当前对象是否拥有了写锁,如果已经拥有,则直接获取失败。
    • 如果没有写锁,就表示当前对象没有排他锁(写锁),则当前线程会尝试给对象加锁。
    • 如果当前线程已经持有了该对象的锁,那么直接将读锁数量加1(可重入)。
  • 写锁:
    • 在获取写锁时,会尝试判断当前对象是否拥有了锁(读锁与写锁),只能选其一。如果已经拥有且持有锁的线程并非当前线程,直接获取失败。
    • 如果当前对象没有被加锁,那么写锁就会为当前对象上锁,并且将写锁的个数加1(可重入)。
    • 将当前对象的排他锁线程持有者设为自己(setExclusiveOwnerThread(current));

ReentrantReadWriteLock的ReadLock释放锁的源码分析

image.png

ReentrantReadWriteLock的WriteLock释放锁的源码分析

image.png