AQS概述

AQS概述

AQS 是JUC并发包中ReentrantLock,ReentrantReadWriteLock,CountDownLatch,CyclicBarrier等类的底层实现。
AQS主要是维护了一个CLH阻塞队列(双向队列)


image.png

这个队列中保存的是没有获得锁的线程。

获取锁资源

线程A

ReentrantLock lock = new ReentrantLock(true);
Condition condition = lock.newCondition();

try{
    lock.lock();
    //.....
    condition.await();

 }finally{
    lock.unlock();
 }

具体过程如下:

  • 1.有A,B两个线程去获取资源,A线程通过Lock方法获取锁资源。
  • 2.B线程接着去调用Lock方法想获取已经属于A的锁资源。
  • 3.B线程会因为获取锁失败(通过CAS操作对状态位进行标记来获取锁),被封装成Node节点放入到AQS CLH双向队列中
  • 4.调用LockSupport.park()将线程阻塞挂起。
  • 5.同理其他再想争用线程A锁的线程也会被加入CLH队列中,并被挂起。

condition

我们知道Lock和synchronized的一大区别就是Lock支持条件的,Lock和condition的关系是1:n的,即一个lock可以有多个条件

Lock lock = new ReentrantLock();
Condition condition1 = lock.newCondition();
Condition condition2 = lock.newCondition();
AQS概述_第1张图片
image.png
条件阻塞

Lock和使用condition步骤如下:

  • 1.线程A需要通过lock方法先获得lock锁。
  • 2.当线程A调用到condition.await()释放锁(通过CAS操作对状态进行标记)
  • 3.阻塞线程A
  • 4.线程A封装成node节点放入条件队列中(每个条件有自己的条件队列,和AQS的CLH队列无关)
  • 5.由于资源被释放,因此去AQS中唤起一个之前被阻塞挂起的线程。
条件释放
  try
        {
            lock.lock();
           ...
            condition.signal();
        }
        finally
        {
            lock.unlock();
        }
  • 1.已经有线程A因为lock的条件被加入到条件队列,并且被挂起(但是不会将线程加入AQS阻塞队列,因为条件尚未满足)。同时线程A释放lock锁
  • 2.线程B获取lock锁
  • 3.线程B之行condition.signal将原本已经因为条件不满足加入到条件队列的线程B取出。并将线程B加入到AQS阻塞队列中
  • 4.当线程B之行unlock操作,阻塞队列中的线程A可以进行lock的资源争抢。

AQS概述已经讲完了,下篇介绍下AQS源码层面相关。

参考文章

5分钟入门AQS

你可能感兴趣的:(AQS概述)