[toc]
Lock接口
常用的方法是lock()/unlock()
lock()不能被中断,对应的lockInterruptibly()可以被中断。
1 | public interface Lock { |
ReentrantLock类
ReentrantLock类是基于AQS实现的
1 | package java.util.concurrent.locks; |
AbstractQueuedSynchronizer源码阅读
1 | package java.util.concurrent.locks; |
属性 | 值 | 含义 |
---|---|---|
CANCELLED | 1 | 在同步队列中等待的线程等待超时或被中断,需要从同步队列中剔除该Node的结点,其结点的waitStatus为CANCELLED,即结束状态,进入该状态后的结点将不会再变化。 |
SIGNAL | -1 | 被标识为该等待唤醒状态的后继结点,当其前驱结点的线程释放了同步锁或被取消,将会通知该后继结点的线程执行。说白了,就是处于唤醒状态,只要前驱结点释放锁,就会通知标识为SIGNAL状态的后继结点的线程执行。 |
CONDITION | -2 | 与Condition相关,该标识的结点处于等待队列中,结点的线程等待在Condition上,当其他线程调用了Condition的signal()方法后,CONDITION状态的结点将从等待队列转移到同步队列中,等待获取同步锁。 |
PROPAGATE | -3 | 与共享模式相关,在共享模式中,该状态标识结点的线程处于可运行状态。 |
1 | // waitStatus是当前节点的一个等待状态标志位, |
为什么获取了锁还需要中断线程?
- 当中断线程被唤醒时,并不知道被唤醒的原因,可能是当前线程在等待中被中断,也可能是释放了锁以后被唤醒。因此我们通过Thread.interrupted()方法检查中断标记(该方法返回了当前线程的中断状态,并将当前线程的中断标识设置为False),并记录下来,如果发现该线程被中断过,就再中断一次。
- 线程在等待资源的过程中被唤醒,唤醒后还是会不断地去尝试获取锁,直到抢到锁为止。也就是说,在整个流程中,并不响应中断,只是记录中断记录。最后抢到锁返回了,那么如果被中断过的话,就需要补充一次中断。
1 | // 这个方法其实就是把对应的线程以Node的数据结构形式加入到双端队列里, |