1、作用
2、两个核心实现
3、五个核心组成
4、设计模式
5、与锁的区别
tryAcquire(int)和tryRelease(int)一样,这个方法是需要独占模式的自定义同步器去实现的。
protected boolean tryRelease(int arg) {
throw new UnsupportedOperationException();
}
如果前驱正常,那就把前驱的状态设置成SIGNAL,告诉它拿完号后通知自己一下
- SIGNAL(-1):表示后继结点在等待当前结点唤醒。后继结点入队时,会将前继结点的状态更新为SIGNAL。
acquire()
- 调用自定义同步器的tryAcquire()尝试直接去获取资源,如果成功则直接返回;
- 没成功,则addWaiter()将该线程加入等待队列的尾部,并标记为独占模式;
- acquireQueued()使线程在等待队列中休息,有机会时(轮到自己,会被unpark())会去尝试获取资源。获取到资源后才返回。如果在整个等待过程中被中断过,则返回true,否则返回false。
- 如果线程在等待过程中被中断过,它是不响应的。只是获取资源后才再进行自我中断selfInterrupt(),将中断补上。
acquireQueued():
- 结点进入队尾后,检查状态,找到安全休息点;
- 调用park()进入waiting状态,等待unpark()或interrupt()唤醒自己;
- 被唤醒后,看自己是不是有资格能拿到号。如果拿到,head指向当前结点,并返回从入队到拿到号的整个过程中是否被中断过;如果没拿到,继续流程1。
release(int):
- 一句话概括:用unpark()唤醒等待队列中最前边的那个未放弃线程
- release()是根据tryRelease()的返回值来判断该线程是否已经完成释放掉资源了
acquireShared():
- tryAcquireShared()尝试获取资源,成功则直接返回;
- 失败则通过doAcquireShared()进入等待队列park(),直到被unpark()/interrupt()并成功获取到资源才返回。整个等待过程也是忽略中断的。
- 其实跟acquire()的流程大同小异,只不过多了个自己拿到资源后,还会去唤醒后继队友的操作(这才是共享嘛)。
releaseShared()
- 独占模式下的tryRelease()在完全释放掉资源(state=0)后,才会返回true去唤醒其他线程
- 共享模式实质就是控制一定量的线程并发执行,那么拥有资源的线程在释放掉部分资源时就可以唤醒后继等待结点。