高性能解决线程饥饿的利器 StampedLock( 三 )
- 如果写锁未被占用 , 则立即尝试获取读锁 , 通过 CAS 修改状态为标志成功则直接返回 。
- 如果写锁被占用 , 则将当前线程包装成 WNode 读节点 , 并插入等待队列 。 如果是写线程节点则直接放入队尾 , 否则放入队尾专门存放读线程的 WNode cowait 指向的栈 。 栈结构是头插法的方式插入数据 , 最终唤醒读节点 , 从栈顶开始 。
- 想将头结点等待状态设置为 0, 标识即将唤醒后继节点 。
- 唤醒后继节点通过 CAS 方式获取锁 , 如果是读节点则会唤醒 cowait 锁指向的栈所有读节点 。
unlockRead(long stamp) 如果传入的 stamp 与锁持有的 stamp 一致 , 则释放非排它锁 , 内部主要是通过自旋 + CAS 修改 state 成功 , 在修改 state 之前做了判断是否超过读线程数限制 , 若是小于限制才通过 CAS 修改 state 同步状态 , 接着调用 release 方法唤醒 whead 的后继节点 。
释放写锁
unlockWrite(long stamp) 如果传入的 stamp 与锁持有的 stamp 一致 , 则释放写锁 , whead 不为空 , 且当前节点状态 status != 0 则调用 release 方法唤醒头结点的后继节点线程 。
总结StampedLock 并不能完全代替ReentrantReadWriteLock, 在读多写少的场景下因为乐观读的模式 , 允许一个写线程获取写锁 , 解决了写线程饥饿问题 , 大大提高吞吐量 。
在使用乐观读的时候需要注意按照编程模型模板方式去编写 , 否则很容易造成死锁或者意想不到的线程安全问题 。
它不是可重入锁 , 且不支持条件变量 Conditon 。 并且线程阻塞在 readLock() 或者 writeLock() 上时 , 此时调用该阻塞线程的 interrupt() 方法 , 会导致 CPU 飙升 。 如果需要中断线程的场景 , 一定要注意调用悲观读锁 readLockInterruptibly() 和写锁 writeLockInterruptibly() 。
【高性能解决线程饥饿的利器 StampedLock】另外唤醒线程的规则和 AQS 类似 , 先唤醒头结点 , 不同的是 StampedLock 唤醒的节点是读节点的时候 , 会唤醒此读节点的 cowait 锁指向的栈的所有读节点 , 但是唤醒与插入的顺序相反 。
- 痛点|首个OTA智能社区诞生 解决行业四大痛点
- 恢复|电脑文件不小心被删除了怎么恢复?文件恢复可以用这招解决!
- 路由器|家里无线网经常断网、网速慢怎么办?教你几个小窍门,轻松解决
- 体验|vivo的OriginOS怎么样?体验报告来袭:虽惊艳但核心问题未解决
- 器件|苏州纳米所等在高性能柔性储能器件研究中取得进展
- 手机|手机发热怎么办?手机发烫的解决办法及原因
- 冲突|智能互联汽车:通过数据托管模式解决数据使用方面的冲突
- 业务|社会化用工行业报告:社会化用工潜力大 解决方案服务供应商迎机遇
- 解决问题|新业态应成为劳动权益保护高地
- 驱动|开源之系统:Ubuntu20.04电脑安装无线网卡驱动并解决包依赖关系