同步状态变量: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
表示本线程在获取资源期间,如果被其他线程中断,本线程不会因为中断而取消获取资源,只是将中断标记传递下去。
- 共享模式:允许多个线程同时获取资源;当一个节点的线程获取共享资源后,需要要通知后继共享节点的线程,也可以获取了。共享节点具有传播性,传播性的目的也是尽快通知其他等待的线程尽快获取锁。
- 独占模式: 只能够一个线程占有资源,其它尝试获取资源的线程将会进入到队列等待。
- 响应中断并终止:线程只要被中断就不会获取资源:两种情况的中断:1、刚尝试获取、2、进入队列中等待,前者立即停止获取,后者执行取消逻辑,等待节点变为取消状态
A、B先后进入队列,状态都是0。A获得资源,进入setHeadAndPropagate晋升为head,A进入doReleaseShared尝试唤醒B时,但B还没将A改为signal,因为A还是0,A将状态改为PROPAGATE2 AbstractQueuedSynchronizer学习总结
2.2.2 为什么unparkSuccessor()要从尾部往前遍历
- addWaiter() 或者enq()插入节点时,都是先更新节点的prev域,再更新它前驱的next域。那么通过node.next()取到的后继,后继的prev域一定是指向node本身。如果先更新next域,在更新prev域时出现异常,那么通过.next取到不是完整的节点
- unparkSuccessor()唤醒后继时,Node s = node.next; 通过.next来获取node的后继,后继的prev一定指向node本身
同步器一般包含两种方法,一种是acquire,另一种是release。acquire操作阻塞调用的线程,直到或除非同步状态允许其继续执行。而release操作则是通过某种方式改变同步状态,使得一或多个被acquire阻塞的线程继续执行。
- 同步状态的原子性管理;
- 线程的阻塞与唤醒;
- 队列的管理;
欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) | Powered by Discuz! X3.4 |