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()一样