java AQS、CountDownLatch、ReentrantLock锁实现原理

(一)AQS全名:AbstractQueueSynchronizer,提供了FIFO队列,内部有的主要字段:

private volatile int state;  全局的一个状态字段,不同的实现可以不同的用法。
比如countDownLatch的时候,state初始是一个传入的总值,每当执行一个countDown方法时,state减一直到为0时,就unpark等待的线程。
比如ReentrantLock的时候,state初始为0,大于0时,就说明有线程已经获取到锁。重入锁时,state可以持续增加。释放锁时,就会unpark队列的第一个节点进行唤醒。
private transient volatile Node head; 队列头节点,头节点不存信息,next的下一个节点存信息。
private transient volatile Node tail; 队列尾节点

其中Node结构
 static final class Node {
    int waitStatus;  状态标记,主要是记录这个队列中的这个节点后续还需要执行不
    Node prev;    前一个节点
    Node next;    下一个节点
    Node nextWaiter;  在等待队列中的下一个节点
    Thread thread;   入队列的线程
    }
waitStatus:表示节点的状态,其中包含的状态有: 
   CANCELLED:值为1,表示当前节点被取消;
   SIGNAL:值为-1,表示当前节点的的后继节点将要或者已经被阻塞,在当前节点释放的时候需要unpark后继节点;
   CONDITION:值为-2,表示当前节点在condition等待队列中;
   PROPAGATE:值为-3,表示releaseShared需要被传播给后续节点(仅在共享模式下使用);
    0:无状态,表示当前节点在队列中等待获取锁。

AQS内部提供了上面的这个队列和一些cas指令来改变state状态的操作,

(二)CountDownLatch原理:
    在new CountDownLatch(5)时,AQS中的state就为5,主线程执行await时,会判断sate值是否为0,不为0就调用LockSupport.park进行阻塞主线程,当其他地方执行了countDown方法,就会将state进行减1,如果减到了0,则调用LockSupport.unpark唤醒在AQS队列中的这一条主线程等待节点。

(三)ReentrantLock原理:通过CAS指令 + AQS队列实现对线程加锁。

结构:ReentrantLock实现接口Lock的lock()和unLock()方法,内部有两个内部类公平锁FairSync和非公平锁NonfairSync,这两个类均继承了AbstractQueueSynchronizer(里面存有Node双向链表组成一个队列,还有head,tail节点,state状态,waitStatus状态)

一、非公平锁加锁过程:

    1、当线程调用lock方法获取锁,通过cas的方式去设置state状态获取锁,如果获取成功则将exclusiveOwnerThread变量设置为当前线程。并返回true。业务正常执行。

    2、当第一次获取锁失败后,判断state是否为0,如果不为0,则判断当前线程是否与exclusiveOwnerThread线程一样(可重入性),相当则state加1,返回true。 如果state==0,则继续尝试获取锁,若获取成功,则设置变量并返回true

       若返回为false,则进入如下面第三步。

  3、创建一个node节点并进行入队列:pre指向tail节点,tail节点的next执行新节点。

  4、队列中节点的waitStatus状态进行设置:如果新节点的pre节点waitStatus状态是singnal(-1),则通过LockSupprt.park方法阻塞当前线程。(内部是调用unsafe的方法对线程),如果新节点的pre节点是大于0,说明这些节点已经废弃,可以跳过,直接继续找前面的节点,直到找到节点状态小于0的,然后设置为signal,并设置为新节点的pre。然后阻塞当前线程。

5、当调用unlock时,会对state变量减1(考虑重入情况),当state==0时,再设置exclusiveOwnerThread==null。然后对队列头节点线程唤醒。通过LockSupport.unpark方式。

二、公平锁的加锁过程:

1、线程调用lock方法时,不会去尝试获取锁,判断state是否为0,如果不为0,则判断当前线程是否与exclusiveOwnerThread线程一样(可重入性),一样则返回true,如果state==0, 且队列是空的,则会尝试获取锁。获取成功,则返回true,执行业务。

   如果获取锁失败或队列不是空。则创建一个新节点node,然后如队列。与非公平锁流程类似。

参考一些优秀解析:
https://www.cnblogs.com/waterystone/p/4920797.html

https://blog.csdn.net/fuyuwei2015/article/details/83719444

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值