7 ReentrantLock底层

目录

1 管程

2 AQS原理分析

2.1 AQS简介

2.2 AQS核心结构

2.3 AQS两种队列

2.3.1 同步等待队列

 2.3.2 条件等待队列

3 ReentrantLock源码

3.1 公平/非公平

3.2 可重入锁

3.3 总体流程

3.3.1 加锁

 3.3.2 解锁


1 管程

7 ReentrantLock底层_第1张图片

 Java中对管程的两种实现:

        sychronized:Object Monitor机制

        AQS:JUC并发包 Lock实现

2 AQS原理分析

2.1 AQS简介

        java.util.concurrent包都是围绕共同的行为,如:等待队列、条件队列、独占获取、共享获取等;而这些基本上由AQS提供(AbstractQueuedSynchronizer)

        Lock、Latch、Barrier等,都是基于AQS来实现

                内部类Sync继承AQS

                将同步器调用的方法映射到Sync对应的方法

        AQS具备的特性

                阻塞等待队列

                共享/独占

                公平/非公平

                可重入

                允许中断

2.2 AQS核心结构

资源可用状态:volatile int state

        getState();setState();compareAndSetState()

两种资源访问方式:

        Exclusive-独占:只允许一个线程执行;ReentrantLock

        Share-共享:多个线程可以同时执行;Semaphore、CountDownLatch

主要方法:

        isHeldExclusively():线程是否在独占资源,与条件condition配合使用

        tryAcquire(int):独占方式,尝试获取资源

        tryRelease(int):独占方式,尝试释放资源

        tryAcquireShared(int):共享方式,尝试获取资源;负数-失败,0-成功且无剩余资源,正数-成功且有剩余资源

        tryReleaseShared(int):共享方式,尝试释放资源;true-释放后允许唤醒剩余节点,否则false

2.3 AQS两种队列

        同步等待队列:获取锁失败时入队的线程

        条件等待队列:调用await()时释放锁,线程加入条件队列;调用signal()唤醒,将线程从条件队列移入同步队列,等待再次获取锁

        AQS 5个节点状态:

                0,初始化状态,节点在sync队列中,等待获取锁

                CANCELLED=1,当前线程被取消

                SIGNAL=-1,当前节点的后继节点包含的线程需要运行,也就是unpark

                CONDITION=-2,当前节点在等待condition,也就是在condition队列中

                PROPAGATE=-3,当前场景下后续的acquireShared能够执行

2.3.1 同步等待队列

        1 当前线程获取同步状态失败时,AQS会将当前信息封装成Node,并加入同步队列,阻塞当前线程

        2 同步状态释放时,会把首节点唤醒(公平锁),使其再次尝试获取同步状态

        3 signal()或signalAll()将条件队列的节点转移到同步队列(条件队列转同步队列

7 ReentrantLock底层_第2张图片

 2.3.2 条件等待队列

通过单向链表保存,使用nextWaiter连接

        调用await()方法阻塞线程

        当前线程位于同步队列头节点,调用await()方法进行阻塞(同步队列转条件队列

3 ReentrantLock源码

3.1 公平/非公平

7 ReentrantLock底层_第3张图片

公平:

final void lock() {
    acquire(1);
}

非公平:

final void lock() {
    if (compareAndSetState(0, 1))
        setExclusiveOwnerThread(Thread.currentThread());
    else
        acquire(1);
}

3.2 可重入锁

7 ReentrantLock底层_第4张图片

3.3 总体流程

3.3.1 加锁

执行3.1 lock.lock()方法后:

7 ReentrantLock底层_第5张图片

 尝试3.2 tryAcquire(),若获取不到尝试加入同步队列中:

7 ReentrantLock底层_第6张图片

7 ReentrantLock底层_第7张图片

当前线程获取不到资源时,需要将同步队列的head节点的线程提出来去获取锁资源

7 ReentrantLock底层_第8张图片

 3.3.2 解锁

7 ReentrantLock底层_第9张图片

 若不是重入锁,则将当前ower线程置空、setState7 ReentrantLock底层_第10张图片

 将下一个节点唤醒

7 ReentrantLock底层_第11张图片

 7 ReentrantLock底层_第12张图片

你可能感兴趣的:(#,并发编程,java,开发语言)