-
概念
-
AQS(AbstractQueuedSynchronizer)是一个抽象的队列同步器,通过维护一个共享资源状态State和一个FIFO的线程等待队列来实现一个多线程访问共享资源的同步框架
-
AQS提供了一个模板,可以通过AQS实现不同的同步器,ReentrantLock、Semaphore都是基于AQS
-
多个线程竞争共享资源变量(state)被阻塞时就会进入等待队列中
-
-
state(共享资源变量)
-
Abstract Queued Synchronizer 维护了 volatile int 类型的变量,用于表示当前的同步状态
-
volatile虽然不能保证操作的原子性,但是能保证当前变量state的可见性
-
-
-
FIFO等待队列
-
多个线程竞争共享资源变量(state)被阻塞时就会进入等待队列中
-
-
ReentrantLock加锁解锁
-
加锁
-
线程 A、B、C 同时抢占锁,此时线程 B 抢占成功,线程 A、C 则失败
-
线程 B 抢占锁的过程中把 state 通过 cas 更新为 1,并且设置当前线程同步器的持有者是线程B
-
设置当前线程同步器的持有者是线程B是为了防止抢占
-
实现可重入,也就是我当前线程B可以在我没有释放锁的前提下再一次获得锁
-
-
线程 A、C 因为更新失败,所以也就抢占失败
-
抢占锁失败的线程,都会被放入到一个 FIFO 的线程等待队列中(双向链表)
-
head、tail 分别指向队列的头和尾
-
-
解锁
-
线程 B 通过 cas 把 state 更新为 0
-
唤醒等待队列中head节点线程 A
-
-
公平锁、非公平锁
-
公平锁
-
按照队列中的等待顺序,依次取队头的线程(比如上面的例子中,下一个获取锁的线程一定是线程 A)
-
-
非公平锁
-
在释放锁后,如果有新的线程尝试获取锁,有可能会抢占成功(比如在线程B释放锁的瞬间,有个 新的线程 D,尝试获取锁,有很大几率会抢占成功)
-
-
-
-
Locksupport
-
在 AQS 中,队列中线程的阻塞唤醒都是通过 LockSupport 实现的
-
LockSupport类的核心方法
-
park():阻塞当前调用线程
-
unpark():唤醒指定线程
-
-
相比Object 类中的 wait()、notify()、notifyAll()区别
-
wait/notify/notifyAll 必须在 synchronized中使用
-
LockSupport 操作更精准,可以准确地唤醒某一个线程
-
-