blog » Java/J2EE » AQS架构

AQS架构

1. LockSupport类
AQS架构使用LockSupport来实现线程的休眠,时间性休眠,唤醒…

2. ‍AQS架构-所有同步器的基本架构
—– a. 基于‍‍AQS架构的同步器基本上只需要实现四个函数
1. tryAcqurie(int) — 线程会调用这个函数来做能否互斥的获取同步器资源的尝试的逻辑
2. tryRelease(int) — ‍线程会调用这个函数来做能否互斥的释放同步器资源的尝试的逻辑
3. tryAcqurieShared(int) — ‍线程会调用这个函数来做能否共享的获取同步器资源的尝试的逻辑
‍4. tryReleaseShared(int) — ‍ ‍线程会调用这个函数来做能否共享的释放同步器资源的尝试的逻辑

—– b. 基于AQS架构同步器分为
互斥同步器 例如‍ReentrantLock
共享同步器 例如‍Semaphore
互斥和共享共存的同步器‍ReentrantReadWriteLock

接下来会有文章依次介绍这些同步器的实现

—– c. AQS数据结构
1. 对于首次进入时获取资源失败的Thread,会将其封装到一个NODE数据块里面
2. 会维护两个NODE引用,分别指向NODE双向链表的头和尾,这样来实现FIFO
3. 对于同步器所拥有的资源就是使用一个INT来表示,这也就是‍互斥和共享共存的
同步器‍同时共享的线程只能是2个BYTE能表示的长度的原因,所有又推出了一个LONG型的AQS架构

—– d. AQS核心代码
1. acquireQueued() 实现了线程不可中断模式下的互斥获取资源
其主要逻辑是一个死循环
a. 线程所属的NODE->prev是HEAD才会调用‍tryAcqurie执行尝试获取锁的逻辑
b. 如果尝试获取锁成功则head=NODE,以及一个释放HARD REFERENCE的操作
c. 返回线程在WAIT期间是否被标记中断 —> 线程摆脱同步器的控制
d. 对‍‍tryAcqurie尝试失败后是否需要WAIT做出判断 —- 重点处
1. 如果前一个NODE处于WAIT则它一定要WAIT
2. 如果前一个NODE处于CANCEL则做一个链表的删除工作
3. 如果前一个NODE是最后加入的则将其标记为WAIT
4. 2和3会让线程再做一次尝试,不会阻塞线程
e. 如果线程需要阻塞则调用‍LockSupport.park阻塞,两种方式会让线程醒来
1. 线程被标记中断
2. 别的线程‍用‍LockSupport.unpark了它,有线程释放了互斥资源
f. 线程醒来循环到a
g. 程序的逻辑就是一个尝试获取资源,线程阻塞,被唤醒的轮回

2. ‍doAcquireInterruptibly()‍实现了线程可中断模式下的互斥获取资源
其原理和‍acquireQueued()一样,不同之处是线程在被中断后即在1.e.1条件下会直接退出死循环

3. ‍doAcquireNanos‍()‍实现了线程可中断+记时模式下的互斥获取资源
a. 在阻塞前会先计算阻塞的时间,进入休眠
b. 如果被中断则会判断时间是否到了
1. 如果没到则且被其他线程设置了中断标志,退出那个轮回,抛出中断异常,如果没有被设置中断标记则是前一个线程
释放了资源再唤醒了它,其继续走那个轮回,轮回中,如果tryAcquire成功则摆脱了同步器的控制,否则回到a
2. 如果时间到了则退出轮回,获取资源失败

4. release()实现了互斥资源的释放,最主要的工作就是将其下一个线程唤醒‍1.e.2

5. doAcquireShared()‍实现了线程不可中断模式下的共享获取资源
a. 线程所属的NODE->prev是HEAD才会调用‍‍tryAcquireShared执行尝试获取锁的逻辑
b. 如果尝试获取锁成功则head=NODE,以及一个释放HARD REFERENCE的操作
此处和互斥的明显区别是,线程在获取成功后如果还有剩余的资源会唤醒其后的线程
也就是如果其下一个线程也是共享的获取资源,其被唤醒的理由多了个
c. 线程在WAIT期间是否被标记中断则标记,因为这期间的标记状态会被清掉 —> 线程摆脱同步器的控制
d. 对‍‍tryAcquireShared尝试失败后是否需要WAIT做出判断 —- 重点处
1. 如果前一个NODE处于WAIT则它一定要WAIT
2. 如果前一个NODE处于CANCEL则做一个链表的删除工作
3. 如果前一个NODE是最后加入的则将其标记为WAIT
4. 2和3会让线程再做一次尝试,不会阻塞线程
e. 如果线程需要阻塞则调用‍LockSupport.park阻塞,三种方式会让线程醒来
1. 线程被标记中断
2. 别的线程‍释放了资源LockSupport.unpark了它
3. 其前一个共享线程醒了以后获取了资源而其还有资源也会唤醒它
f. 线程醒来循环到a
g. 程序的逻辑就是一个尝试获取资源,线程阻塞,被唤醒的轮回

6. ‍doAcquireSharedInterruptibly()‍实现了线程可中断模式下的共享获取资源
其原理和‍‍doAcquireShared()一样,不同之处是线程在被中断后即在5.e.1条件下会直接退出死循环

7. doAcquireSharedNanos()‍实现了线程可中断+记时模式下的共享获取资源
a. 在阻塞前会先计算阻塞的时间,进入休眠
b. 如果被中断则会判断时间是否到了
1. 如果没到则且被其他线程设置了中断标志,退出那个轮回,抛出中断异常,如果没有被设置中断标记则是前一个线程
释放了资源再唤醒了它,其继续走那个轮回,轮回中,如果tryAcquire成功则摆脱了同步器的控制,否则回到a
2. 如果时间到了则退出轮回,获取资源失败

8. ‍releaseShared()和‍release()一样

—————————————–

[来源:http://www.cnblogs.com/mandela/archive/2011/04/08/2009808.html]

This post has already been read 1004 times!

Related posts

RSS 2.0 | leave a response | trackback

发表评论