用大白话解释: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节点,加入到等待队列的队尾,直到什么时候线程A释放了锁它会唤醒等待队列队头的线程。这里还要分为公平锁和非公平锁,默认为非公平锁,公平锁和非公平锁无非就差了一步。如果是公平锁,此时又有外来线程尝试获取锁,它会首先判断一下等待队列是否有第一个节点,如果有第一个节点,就说明等待队列不为空,有等待获取锁的线程,那么它就不会去同步队列中抢占cpu资源。如果是非公平锁的话,它就不会判断等待队列是否有第一个节点,它会直接前往同步对列中去抢占cpu资源。

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

猜你喜欢

转载自blog.csdn.net/qq_37685457/article/details/89704124