目录
1 管程
2 AQS原理分析
2.1 AQS简介
2.2 AQS核心结构
2.3 AQS两种队列
2.3.1 同步等待队列
2.3.2 条件等待队列
3 ReentrantLock源码
3.1 公平/非公平
3.2 可重入锁
3.3 总体流程
3.3.1 加锁
3.3.2 解锁
Java中对管程的两种实现:
sychronized:Object Monitor机制
AQS:JUC并发包 Lock实现
java.util.concurrent包都是围绕共同的行为,如:等待队列、条件队列、独占获取、共享获取等;而这些基本上由AQS提供(AbstractQueuedSynchronizer)
Lock、Latch、Barrier等,都是基于AQS来实现
内部类Sync继承AQS
将同步器调用的方法映射到Sync对应的方法
AQS具备的特性:
阻塞等待队列
共享/独占
公平/非公平
可重入
允许中断
资源可用状态:volatile int state
getState();setState();compareAndSetState()
两种资源访问方式:
Exclusive-独占:只允许一个线程执行;ReentrantLock
Share-共享:多个线程可以同时执行;Semaphore、CountDownLatch
主要方法:
isHeldExclusively():线程是否在独占资源,与条件condition配合使用
tryAcquire(int):独占方式,尝试获取资源
tryRelease(int):独占方式,尝试释放资源
tryAcquireShared(int):共享方式,尝试获取资源;负数-失败,0-成功且无剩余资源,正数-成功且有剩余资源
tryReleaseShared(int):共享方式,尝试释放资源;true-释放后允许唤醒剩余节点,否则false
同步等待队列:获取锁失败时入队的线程
条件等待队列:调用await()时释放锁,线程加入条件队列;调用signal()唤醒,将线程从条件队列移入同步队列,等待再次获取锁
AQS 5个节点状态:
0,初始化状态,节点在sync队列中,等待获取锁
CANCELLED=1,当前线程被取消
SIGNAL=-1,当前节点的后继节点包含的线程需要运行,也就是unpark
CONDITION=-2,当前节点在等待condition,也就是在condition队列中
PROPAGATE=-3,当前场景下后续的acquireShared能够执行
1 当前线程获取同步状态失败时,AQS会将当前信息封装成Node,并加入同步队列,阻塞当前线程
2 同步状态释放时,会把首节点唤醒(公平锁),使其再次尝试获取同步状态
3 signal()或signalAll()将条件队列的节点转移到同步队列(条件队列转同步队列)
通过单向链表保存,使用nextWaiter连接
调用await()方法阻塞线程
当前线程位于同步队列头节点,调用await()方法进行阻塞(同步队列转条件队列)
公平:
final void lock() {
acquire(1);
}
非公平:
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
执行3.1 lock.lock()方法后:
尝试3.2 tryAcquire(),若获取不到尝试加入同步队列中:
当前线程获取不到资源时,需要将同步队列的head节点的线程提出来去获取锁资源
将下一个节点唤醒