JUC 之 Lock内部组件(队列同步器、阻塞与唤醒、Condition)
一、队列同步器(AbstractQueuedSynchronizer)
同步器使用了一个int成员变量表示同步状态,通过内置的FIFO双向队列来完成资源获取线程的排队工作。
1、主要方法
- getState():获取当前同步状态。
- setState(int newState):设置当前同步状态。
- compareAndSetState(int expect,int update):使用CAS设置当前状态,该方法能够保证状态设置的原子性。
2、同步器是怎么借助 FIFO队列 实现?
-
同步器拥有首节点(head)和尾节点(tail)。
-
获取同步状态失败的线程将被构造成一个node(包含线程引用、等待状态以及前驱和后继节点), 并通过CAS操作加入FIFO队列末尾,同时阻塞该线程。
CAS设置尾节点:compareAndSetTail(Node expect,Node update),比较当前线程拿到的尾节点和当前同步器中的尾节点,成功,则设置为新的尾节点。
-
当同步状态释放,会把FIFO中的首节点唤醒,让其再次尝试获取线程。
设置首节点是通过获取同步状态成功的线程来完成的,所以是线程安全的,直接替换引用即可。
二、LockSupport (线程阻塞与唤醒)
三、Condition
ConditionObject是同步器AbstractQueuedSynchronizer的内部类,因为Condition的操作需要获取相关联的锁
一般都会将Condition对象作为成员变量。
当调用await()方法后,当前线程会释放锁并在此等待,
而其他线程调用Condition对象的signal()方法通知当前线程后,当前线程才从await()方法返回,并且在返回前已经获取了锁。
Condition如何实现的?
Condition主要包括等待队列、等待、通知
等待队列
等待队列是一个FIFO的队列(类比成同步队列理解即可),(节点则是复用了同步器的类)
当某个线程调用了await方法后,即从当前线程开始构建节点,并加入等待队列末尾
等待
调用Condition的await()方法后,当前线程进入等待队列并释放锁,同时线程状态变为等待状态
通知
调用Condition的signal()方法,将会唤醒在等待队列的首节点,在唤醒节点之前,会将节点移到同步队列中。
- 当前线程加入等待队列
- 节点从等待队列移动到同步队列的过程