| 学习路线指引(点击解锁) | 知识定位 | 人群定位 |
|---|---|---|
| 🧡 Python实战微信订餐小程序 🧡 | 进阶级 | 本课程是python flask+微信小程序的完美结合,从项目搭建到腾讯云部署上线,打造一个全栈订餐系统。 |
| 💛Python量化交易实战💛 | 入门级 | 手把手带你打造一个易扩展、更安全、效率更高的量化交易系统 |
目录* 1 疑点todo和解疑
同步状态变量:state就是那个共享资源(private volatile int state;) Lock类继承AQS类并定义lock()、unLock()的方法,表示获取锁和释放锁。多线程并发访问同一个lock实例,lock()方法会cas修改state变量,修改成功的线程获得锁,其他线程进入AQS队列等待。
没有必要!sync队列是双向链表结构,出队时,head交替方式,只需要修改head和head后继2个节点引用关系;固定head,就要修改head,head后继,以及head后继的后继 共3个节点。显然前者效率更高

不存在的,因为经过判断得出此时node就是head的后继。并且必须由这个取消节点node来唤醒后继,要不node线程结束后,就没有线程能够唤醒队列里的其他节点了。
先说结果:由抢到锁的那个线程来唤醒!
上述的场景是存在的,例如在非公平锁模式中,B线程被A线程唤醒,A结束,B成为head,B去执行tryAcquire(),但此时C线程抢占到锁,B执行tryAcquire()没有拿到锁,再次park阻塞。C线程执行结束后将A唤醒
只有将前置节点状态改为SIGNAL,才能确保当前节点可以被前置unPark唤醒。也就是说阻塞自己前先保证一定能够被唤醒。因为代码中:
独占模式下,唤醒后继前先限制:h.waitStatus != 0
共享模式下,唤醒后继前先限制:h.waitStatus=SIGNAL
表示本线程在获取资源期间,如果被其他线程中断,本线程不会因为中断而取消获取资源,只是将中断标记传递下去。
When acquired in exclusive mode,
* attempted acquires by other threads cannot succeed. Shared mode
* acquires by multiple threads may (but need not) succeed. This class
* does not "understand" these differences except in the
* mechanical sense that when a shared mode acquire succeeds, the next
* waiting thread (if one exists) must also determine whether it can
* acquire as well. Threads waiting in the different modes share the
* same FIFO queue.
- 共享模式:允许多个线程同时获取资源;当一个节点的线程获取共享资源后,需要要通知后继共享节点的线程,也可以获取了。共享节点具有传播性,传播性的目的也是尽快通知其他等待的线程尽快获取锁。
- 独占模式: 只能够一个线程占有资源,其它尝试获取资源的线程将会进入到队列等待。
- 响应中断并终止:线程只要被中断就不会获取资源:两种情况的中断:1、刚尝试获取、2、进入队列中等待,前者立即停止获取,后者执行取消逻辑,等待节点变为取消状态
A、B先后进入队列,状态都是0。A获得资源,进入setHeadAndPropagate晋升为head,A进入doReleaseShared尝试唤醒B时,但B还没将A改为signal,因为A还是0,A将状态改为PROPAGATE
对于AbstractQueuedSynchronizer的分析,最核心的就是sync queue的分析。
//addWaiter():
node.prev = pred; // 1 更新node节点的prev域
if (compareAndSetTail(pred, node)) {
pred.next = node; //2 更新node前驱的next域
return node;
}
//enq():
node.prev = t; // 1 更新node节点的prev域
if (compareAndSetTail(t, node)) {
t.next = node;//2 更新node前驱的next域
return t;
}
//unparkSuccessor():
Node s = node.next; //通过.next来直接获取到节点的后继节点,这个节点的后继的prev一定指向节点本身
//....
if (s != null)
LockSupport.unpark(s.thread);
- addWaiter() 或者enq()插入节点时,都是先更新节点的prev域,再更新它前驱的next域。那么通过node.next()取到的后继,后继的prev域一定是指向node本身。如果先更新next域,在更新prev域时出现异常,那么通过.next取到不是完整的节点
- unparkSuccessor()唤醒后继时,Node s = node.next; 通过.n