AQS
AQS中同步状态
其中state表示同步状态,为32位整数,用来表示锁的数量。
AQS主体流程
AQS中提供了获取和释放锁有两种模式:独占式和共享式。
1. 独占模式:
1) acquire:以独占的模式获取对象,忽略中断。
2) acquireInterruptibly:以独占模式获取对象,如果中断则停止。
3) release:以独占模式释放对象。
2. 共享模式:
1) acquireShared:以共享模式获取对象,忽略中断。
2) acquireSharedInterruptibly:以共享模式获取对象,如果被中断则中止。
3) releaseShared:以共享模式释放对象。
PS:独占模式可以视为共享模式的特例,共享数量为1.
3. 主体流程:
1) 线程通过acquireSharedInterruptibly获取锁,操作完成后。
2) 通过releaseShared来释放锁。
3) 程序获取锁失败后(通过调用acquireSharedInterruptibly),将进入等待队列,然后进入阻塞状态(经过一些判断之后)
4) 当另一个线程释放锁后(通过调用releaseShared),将执行唤醒阻塞线程的操作;被唤醒的线程将把自己移出等待队列,并执行一些其它操作
等待队列
AQS中使用FIFO的队列来管理等待获取锁的线程。
1. 主要流程:
1) 入队列:线程获取锁失败后,调用doAcquireSharedInterruptibly方法。
a) 创建一个新的结点。
b) 将结点添加到等待队列队尾。
c) 将线程阻塞。
2) 唤醒:其它线程释放锁资源,调用releaseShared中doReleaseShared方法。
a) 获取队列中的第一个结点。
b) 将节点对应线程唤醒。
c) 该线程将尝试获取锁,成功后将自己移除等待队列。
d) 判断是否仍然有空闲锁,若有则继续唤醒下一个结点。
2. 每次只会唤醒第一个节点,如果同时释放多个锁,后续的节点将由前面被唤醒的节点来唤醒,尽量减少数据竞争。
阻塞机制
1. 作用:
1) 阻塞新添加到等待队列中的线程。
2) 唤醒等待队列中对头的等待线程。
2. 实现:使用Unsafe的park和unpark实现的
Condition
1. 作用:Condition实例始终被绑定到一个锁(Lock)上,Lock替代了Java的synchronized方法,而Condition则替代了Object的监视器方法,包括wait、notify和notifyAll。即起到线程间通信的作用。提供await、signal和signalAll方法。
2. 使用:
3. 主要方法:
1) Await():阻塞当前前程,直到有信号到来唤醒它。
a) 可能被唤醒的时机:
Ø 其他某线程调用了此Condition的signal()方法
Ø 其他某线程调用此Condition的SignalAll()方法
Ø 其他某线程中断当前线程
Ø 超过指定等待时间
Ø 发生“虚假唤醒”
否则一直处于等待状态
b) 阻塞过程:
1. 如果当前线程被中断,则抛出中断异常;
2. 入队:将当前线程放置到Condition的等待队列中;
3. 释放锁资源:释放当前线程的锁,并且保存锁定状态;
4. 循环检测:在收到信号、中断或超时前,一直阻塞;
5. 放行:使用保存的锁定状态重新获取锁;
6. 如果步骤4的阻塞过程中发生中断,则抛出中断异常
PS:将阻塞放入到循环中---à防止“虚假唤醒”
保存锁定状态---------à使用排他模式
2) Signal():唤醒一个线程。即将当前Condition的等待队列中的第一个结点移动到拥有锁的等待队列中等待执行。
3) signalAll():将当前Condition的等待队列中的所有结点移到拥有锁的等待队列中。等待执行。