ReentrantLock可重入式锁

首先看下AQS以及CLH
在AQS(AbstractQueuedSynchronizer)中,没有获取到锁的线程我们使用CLH队列进行储存
CLH是一个双向链表,链表的元素是Node节点,Node类是AQS的内部类,Node主要存储以下信息:

共享模式的标记
static final Node SHARED = new Node();

独占模式的标记
static final Node EXCLUSIVE = null;

waitStatus变量的值,标志着线程被取消
static final int CANCELLED =  1;

waitStatus变量的值,标志着后继线程(即队列中此节点之后的节点)需要被阻塞.(用于独占锁)
static final int SIGNAL    = -1;

waitStatus变量的值,标志着线程在Condition条件上等待阻塞.(用于Condition的await等待)
static final int CONDITION = -2;

waitStatus变量的值,标志着下一个acquireShared方法线程应该被允许。(用于共享锁)
static final int PROPAGATE = -3;

标记着当前节点的状态,默认状态是0, 小于0的状态都是有特殊作用,大于0的状态表示已取消
volatile int waitStatus;

prev和next实现一个双向链表
volatile Node prev;
volatile Node next;

该节点拥有的线程
volatile Thread thread;

两种作用:
1. 表示下一个在Condition条件上等待的节点
2. 表示是共享模式或者独占模式,注意第一种情况节点一定是共享模式
Node nextWaiter;


通过ReentrantLock加锁时会调用内部类Sync的lock方法,Sync有两个子类NonfairSync(非公平锁)和FairSync(公平锁),
子类重写了父类的lock方法,在lock方法中会调用Sync的父类AbstractQueuedSynchronizer的acquire方法,这个方法完成两步操作:
第一步
该方法首先会回调孙子类NonfairSync或FairSync的tryAcquire方法,然后调用Sync的nonfairTryAcquire方法,
这个方法会获取当前的state值(该值理解成信号量,标记了当前有多少个信号量可以使用),
如果发现state值为0,那么就通过CAS操作更新state的值,默认更新为1;
如果不为零,那么判断当前线程是不是独占锁拥有的的线程,如果是,就在原来的state值上默认加1
第二步
调用acquireQueued方法
先调用addWaiter方法为当前线程创建一个节点node,并插入队列中,
然后调用acquireQueued方法去获取锁,该方法会取当前节点和当前节点的上一个节点,
如果没有上一节点,尝试获取锁,获取成功了就返回
如果不成功或者有上一节点,就会执行shouldParkAfterFailedAcquire方法,
该方法会判断当前节点的上一节点的waitStatus是否为-1(阻塞),如果为-1,则调用LockSupport.pack(this)来阻塞该节点线程;
如果当前节点的上一节点的waitStatus大于0(即取消),那么就移除该节点;
如果当前节点的上一节点的waitStatus等于0,那么就把他的waitStatus设置为-1(阻塞)

所以这里的阻塞就是通过LockSupport来实现的,唤醒也同样是通过LockSupport来实现的

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值