1、什么是AQS
AQS为抽象队列同步器,是一个用来构建锁和同步器的框架,使用 AQS 能简单且高效地构造出应用广泛的大量的同步器。
首先,抽象代表它是一个抽象类,继承后需要实现方法,队列主要是因为其内部有一个CLH队列用于保证线程的阻塞与唤醒。
2、AQS的原理
如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,那么就需要一套线程阻塞等待以及被唤醒时锁分配的机制,这个机制 AQS 是用 CLH 队列锁实现的,即将暂时获取不到锁的线程加入到队列中
其内部有一个volatile修饰int类型的state变量,该变量用于表示同步状态,为了保证该变量的线程安全,需要volatile和CAS,当该同步状态为锁定状态时,想要访问共享资源的线程将会阻塞并进入CLH队列中等待唤醒。
对state的操作只有三个,getState
,setState
,compareAndSetState
,其中最后哪个就是CAS的体现。
3、AQS的实现
AQS分为独占与共享,
AQS的实现有很多,上面也提到了,AQS用于构建锁和同步器,那么绝大多数锁应该都用到了,下面啊为列举 :
ReentrantLock :独占锁,可重入锁
可以分为公平与非公平,区别在于是否在所释放后抢锁问题。
Semaphore(信号量):共享锁
它默认构造 AQS 的 state 为 permits。当执行任务的线程数量超出 permits,那么多余的线程将会被放入阻塞队列 Park,并自旋判断 state 是否大于 0。只有当 state 大于 0 的时候,阻塞的线程才能继续执行,此时先前执行任务的线程继续执行 release 方法,release 方法使得 state 的变量会加 1,那么自旋的线程便会判断成功。
CountDownLatch:共享锁,不能复用
允许 count
个线程阻塞在一个地方,直至所有线程的任务都执行完毕。
它默认构造 AQS 的 state
值为 count
。当线程使用 countDown()
方法时,其实使用了tryReleaseShared
方法以 CAS 的操作来减少 state
,直至 state
为 0 。当调用 await()
方法的时候,如果 state
不为 0,那就证明任务还没有执行完毕,await()
方法就会一直阻塞,也就是说 await()
方法之后的语句不会被执行。然后,CountDownLatch
会自旋 CAS 判断 state == 0
,如果 state == 0
的话,就会释放所有等待的线程,await()
方法之后的语句得到执行。
CyclicBarrier:共享锁,可复用
CyclicBarrier 和 CountDownLatch 非常类似,它也可以实现线程间的技术等待,但是它的功能比 CountDownLatch 更加复杂和强大。主要应用场景和 CountDownLatch 类似。
让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活。CyclicBarrier 默认的构造方法是 CyclicBarrier(int parties)
,其参数表示屏障拦截的线程数量,每个线程调用await
方法告诉 CyclicBarrier 我已经到达了屏障,然后当前线程被阻塞。