多线程(七)—— ReentrantLock源码解析

目录

    • 可重入锁有两种实现方式 :
    • 一、AbstractQueuedSynchronizer源码解析
      • 1、继承关系
      • 2、构造函数
      • 3、属性
    • 二、ReentrantLock源码解析
      • 1、继承关系
      • 2、构造函数
      • 3、属性和内部类
        • Sync类源码(公平锁和非公平锁的父类):
          • NonfairSync(非公平性锁)源码:
          • FairSync(公平性锁)源码
      • 4、方法

可重入锁有两种实现方式 :

1、公平锁:先来后到,先来抢锁的线程先执行;
2、非公平锁:谁抢到谁先执行,不管你先来后到顺序的;
而这两种锁的实现都用到了AbstractQueuedSynchronizer这个类(简称AQS,实现锁很重要的一个类),这个类基于FIFO队列,可以用于构建锁或者其他相关同步装置的基础框架。该同步器(以下简称同步器)利用了一个int来表示状态,所以要了解ReentrantLock(可重入锁的实现原理)首先要了解AQS,因此先来看看AQS的实现:

一、AbstractQueuedSynchronizer源码解析

1、继承关系

多线程(七)—— ReentrantLock源码解析_第1张图片

2、构造函数

在这里插入图片描述

3、属性

顺便也把属性相关的内部类也分析了:
多线程(七)—— ReentrantLock源码解析_第2张图片
多线程(七)—— ReentrantLock源码解析_第3张图片
AQS中的state:
state=0 表示锁是空闲状态
state>0 表示锁被占用
state<0 表示溢出
在这里插入图片描述
多线程(七)—— ReentrantLock源码解析_第4张图片
好了,知道这些基础属性和方法就好了,其他的AQS方法在解析ReentrantLock源码的时候调用的时候再说:

下面来看ReentrantLock的源码:

二、ReentrantLock源码解析

1、继承关系

在这里插入图片描述

2、构造函数

多线程(七)—— ReentrantLock源码解析_第5张图片

3、属性和内部类

Sync类源码(公平锁和非公平锁的父类):

多线程(七)—— ReentrantLock源码解析_第6张图片
多线程(七)—— ReentrantLock源码解析_第7张图片

多线程(七)—— ReentrantLock源码解析_第8张图片

NonfairSync(非公平性锁)源码:

从lock()方法开始看:


NonFairSync获取锁总结一下过程就是:
1、第一次通过CAS强制抢锁,抢锁失败则再次尝试性抢锁;
2、第二次尝试性抢锁,首先判断锁是否未占用(state=0),是则直接CAS来获取锁,
获取成功则修改state,且将当前线程计入AQS中,成功返回;在判断锁占用的情况下,占用锁的线程是当前线程,则直接修改state,成功返回;
以上都不满足:
①将当前线程加入到存放线程的双向链表中(如果当前双向链表为空,初始化头节点,头节点是一个什么都没有的空节点,然后添加存放当前线程的节点到链表后面并更新链表的尾指针),
②一直尝试获取锁(将新加入的结点放入队列之后,这个结点有两种状态,要么获取锁,要么就挂起,如果这个节点不是头节点的下一个节点,就看看这个结点是否应该挂起,如果应该挂起,就挂起当前结点,是否应该挂起是shouldParkAfterFailedAcquire方法来判断的,如果当前节点的前驱节点不是头节点,那么前驱节点就会通知它的,他就可以放心挂起了,如果当前节点的前驱节点就是头节点,那么通过tryAcquire尝试获取锁,如果获取锁成功了,把当前节点置为头节点),直至成功;

FairSync(公平性锁)源码

从lock()方法开始看:
多线程(七)—— ReentrantLock源码解析_第9张图片
总结一下 FairSync获取锁的过程:
1、尝试性获取锁
若锁未被占用,判断当前线程是否满足条件(AQS队列为空或者当前线程处于AQS队列的队头),修改state,将当前线程记录到锁上,成功返回
若锁被占用,且是当前线程占有锁,修改state,成功返回
若以上都不满足,则失败返回;
2、若未获取到锁,则即将线程加入AQS中的队列;

在可重入锁里面还有一个ConditionObject,它是Condition接口的唯一实现类,而Condition提供了比wait、notify、notifyAll更为灵活的线程间通信机制,它的源码解析;

最后在说说unlock()方法:
多线程(七)—— ReentrantLock源码解析_第10张图片

4、方法

其他方法就比较简单了,下面是ReentrantLock类的其他方法介绍:

方法 作用
int getHoldCount() 查询当前线程保持此锁定的个数,即调用lock()方法的次数。
int getQueueLength() 返回正等待获取此锁定的预估线程数。
int getWaitQueueLength(Condition condition) 返回与此锁定相关的约定condition的线程预估数。
boolean hasQueuedThread(Thread thread) 、boolean hasQueuedThreads() 查询当前线程是否在等待获取此锁
boolean hasWaiters(Condition condition) 查询是否存在指定Condition的线程正在等待此锁定。
boolean isFair() 如果是公平锁的话返回true(ReentrantLock默认使用的是非公平锁)
isHeldByCurrentThread() 查询当前线程是否保持锁定。
isLocked() 查询是否存在任意线程保持此锁定。
lockInterruptbly() 如果当前线程未被中断,则获取锁定;如果已中断,则抛出异常(InterruptedException)
tryLock() 尝试获取锁定,如果锁定没有被别的线程保持,则获取锁定,即成功获取返回true,否则返回false(锁定已被别的线程获取)
tryLock(long timeout, TimeUnit unit) 尝试获取锁定,如果锁定没有被别的线程保持,则获取锁定,即成功获取返回true,如果没有获取锁定,则等待指定的时间,要是在指定时间内获取锁定,返回true,否则返回false。

区别:
非公平锁获取两次锁;

你可能感兴趣的:(多线程,java,源码解析,多线程)