深度解析:AQS原理

  AQS的全称是AbstractQueuedSynchrizeder(抽象队列同步器)。它是为实现依赖于先进先出等待队列的阻塞锁和各种同步器(Semaphore,CountdownLatch,CyclicBarrier,Exchanger等等)而提供的一种基础框架。

  它内部有一个int类型的state变量,被volatile关键字修饰,保证线程之间的可见。还会维护一个Node内部类(用于生成同步对列和等待队列),并继承过来一个加锁线程。state变量的访问方式有三种:getState(),setState(int),compareAndSetState(int,int)三个方法。AQS定义了两种资源共享的方式,独占模式和共享方式。

  使用此类:

   为了将此类用作同步器的基础,需要适当的重新定义以下方法,这是通过使用getState(),setState(int),compareAndSetState(int,int)三个方法来检查或修改同步状态来实现的。

        tryAcquire(int)       试图在独占模式下获取对象状态,由acquire自动调用,至少调用一次

        tryRelease(int)      试图设置状态来反映独占模式下的一个释放,由release自动调用,至少调用一次

        tryAcquireShared(int)         试图在共享模式下获取对象状态,由acquireShared自动调用,至少调用一次

         tryReleaseShared(int)      试图设置状态来反映共享模式下的一个释放,由releaseShared自动调用,至少调用一次

  默认情况下,每个方法都抛出UnsupportedOperationException。这些方法的实现在内部必须是线程安全的,通常应该很短并且不被阻塞。

 

  ReentrantLock就是使用AQS而实现的一把锁,它实现了可重入锁,公平锁和非公平锁。它有一个内部类用作同步器是Sync,Sync是继承了AQS的一个子类,并且公平锁和非公平锁是继承了Sync的两个子类。ReentrantLock的原理是:假设有一个线程A来尝试获取锁,它会先CAS修改state的值,从0修改到1,如果修改成功,那就说明获取锁成功,设置加锁线程为当前线程。如果此时又有一个线程B来尝试获取锁,那么它也会CAS修改state的值,从0修改到1,因为线程A已经修改了state的值,那么线程B就会修改失败,然后他会判断一下加锁线程是否为自己本身线程,如果是自己本身线程的话它就会将state的值直接加1,这是为了实现锁的可重入。如果加锁线程不是当前线程的话,那么就会将它生成一个Node节点,加入到等待队列。

在加入到等待队列时,先调用addWaiter方法,判断尾节点是否为null,如果为null,就说明当前队列还未初始化,首先要new一个空的Node节点,放在头节点上作为哨兵节点;然后将线程B生成的Node节点放在哨兵节点的后面。然后跳出addWaiter方法,进入到accquireQueue方法,这是一个死循环方法,如下:

首先会判断前驱节点是否为头节点,如果是,调用tryAcquire方法再抢占一下,抢占失败;判断前驱节点是否是SIGNAL(-1)状态,此时不是SIGNAL(-1)是0,为其设置为SIGNAL(-1)状态,返回false,继续执行死循环,判断前驱节点是否为头节点,是,再次尝试抢占一下,抢占失败;再次判断前驱节点是否是SIANAL状态,此时已经变为SIGANL状态,线程执行park方法,真正的进去阻塞状态。 

直到加锁线程释放了当前的锁,此时,会唤醒哨兵节点的下一个节点,让该节点的线程调用unpark方法,唤醒线程,唤醒之后它依然执行死循环方法accquireQueue,还是走判断前驱节点是否为哨兵节点,是,再次尝试抢占锁,此时就能CAS抢占成功;将哨兵节点置为null,将哨兵节点的下一个节点设置为哨兵节点,设置状态为0;

这里还要分为公平锁和非公平锁,默认为非公平锁,公平锁和非公平锁无非就差了一步。如果是公平锁,此时又有外来线程尝试获取锁,它会首先判断一下等待队列是否有第一个节点,如果有第一个节点,就说明等待队列不为空,有等待获取锁的线程,那么它就不会去同步队列中抢占cpu资源。如果是非公平锁的话,它就不会判断等待队列是否有第一个节点,它会直接前往同步对列中去抢占cpu资源。

  以下是ReentrantLock的原理图解,简单明了:

 

  • 6
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值