StampedLock源码分析

本文深入探讨了Java并发工具包中的StampedLock,一种结合读锁、写锁和乐观锁的高级锁机制。它允许高并发读操作,但在不当使用时可能导致死锁和数据一致性问题。文章提供了详细的使用案例和风险说明,旨在帮助开发者理解和安全地利用StampedLock提升性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


title: JUC.StampedLock

StampedLock提纲

StampedLock简介

首先大方向看下StampedLock类图
avatar
从图中可以看出这个锁貌似有点屌屌的有读锁写锁读写锁。这个锁看上去很厉害,其实这个锁不像其它锁那么安全使用,存在很高的风险性。
听说该锁设计之初是为了作为工具类开发其它线程安全组件,用好了提升性能。没用好会发生死锁,CPU飙升耗死资源的情况,以及读写锁脏数据
为什么出现死锁,如果记得我前一章所写的非可重入锁就知道了。这个大哥也是非可重入的,哈哈哈~

至于CPU飙升引用一文章地址* https://m.aliyun.com/yunqi/articles/20340,然后我再解释一下。因为文中老哥没有解释为啥。
当线程被中断的时候被park的线程会继续进入到循环中不断的获取锁到满足条件为止,导致CPU爆炸。
后面我有时间会详细写一篇关于这个问题的文章,以及相比较我引用文章更好理解的例子。
读写锁的脏数据是因为读的时候数据被修改了,不过可以通过貌似有个官方的代码模板的写法可以解决。
就是先使用乐观锁,然后再转为读锁,不让数据被修改了。
在下面我放上了实例代码。
上面介绍了这个锁以及使用风险,咱们继续说说使用场景。
读写锁可以应用在应用缓存方面,比如一方面写一方面缓存数据,并提供读取缓存。

 * class Point {
 *   private double x, y;
 *   private final StampedLock sl = new StampedLock();
 *
 *   void move(double deltaX, double deltaY) { // an exclusively locked method
 *     long stamp = sl.writeLock();
 *     try {
 *       x += deltaX;
 *       y += deltaY;
 *     } finally {
 *       sl.unlockWrite(stamp);
 *     }
 *   }
 *
 *   double distanceFromOrigin() { // A read-only method
 *     long stamp = sl.tryOptimisticRead();
 *     double currentX = x, currentY = y;
 *     if (!sl.validate(stamp)) {
 *        stamp = sl.readLock();
 *        try {
 *          currentX = x;
 *          currentY = y;
 *        } finally {
 *           sl.unlockRead(stamp);
 *        }
 *     }
 *     return Math.sqrt(currentX * currentX + currentY * currentY);
 *   }
 *
 *   void moveIfAtOrigin(double newX, double newY) { // upgrade
 *     // Could instead start with optimistic, not read mode
 *     long stamp = sl.readLock();
 *     try {
 *       while (x == 0.0 && y == 0.0) {
 *         long ws = sl.tryConvertToWriteLock(stamp);
 *         if (ws != 0L) {
 *           stamp = ws;
 *           x = newX;
 *           y = newY;
 *           break;
 *         }
 *         else {
 *           sl.unlockRead(stamp);
 *           stamp = sl.writeLock();
 *         }
 *       }
 *     } finally {
 *       sl.unlock(stamp);
 *     }
 *   }
 * }}

原理剖析

理论上来说StampedLock锁本质上还是基于CAS以及双向队列实现,换汤不换药。这里还是佩服一下 Doug Lea大师。大师对于数据结构的运用还是挺秀的源码都挺好看。

  • 写锁
    writeLock是一个独占锁某时只允许一个线程修改。当前没有读锁或者写锁的时候才可以获取,请求的时候会返回一个stamp标识该锁版本释放的时候需要传入。
  • 读锁
    readLock是一个共享锁,当前没有写锁的时候可以多个线程获取,如果有写锁存在则会造成阻塞。
  • 读写锁
    tryOptimisticRead并没有使用CAS修改锁的状态,仅仅通过位运算测试。如果当前没有线程持有写锁,则简单的返回要给非0的stamp信息。获取stamp后再具体操作数据前还需要调用validate
    验证stamp是否已经不可用,也就是看是否tryOptmisticRead返回stamp期间是否有线程持有了写锁。
    这一章我源代码看的不多,所以写不出什么深入的东西。后续我会持续更新这一章~

欢迎扫码加入知识星球继续讨论
avatar

### CCS烧录代码失败的原因分析 在使用TI毫米波雷达开发过程中,遇到`cannot find file "libsleep_xwr68xx.aer4f"`的报错可能源于以下几个方面: #### 1. 文件路径配置不正确 如果工程中缺少指定库文件 `libsleep_xwr68xx.aer4f` 或者其路径未被正确定义,则可能导致此问题。通常情况下,该文件应位于项目的链接器设置中的库目录下[^1]。 #### 2. 工程依赖缺失 某些必要的源文件或头文件未能正确添加到项目中也可能引发类似的错误。例如,在另一个案例中提到,“DSP2833x_MemCopy.c” 这样的核心组件如果没有加入工程则会触发编译阶段的问题[^2]。 #### 3. 构建工具链异常 构建脚本执行不当或者相关参数设定有误同样会影响最终生成物的质量。比如通过命令行调用 mkimage 实用程序时若选项不符合预期目标架构的要求就会造成不可预见的结果[^3]。 --- ### 解决方案 针对上述几种可能性提供如下建议措施来修复CCS烧录过程中的这些障碍: #### 配置正确的库文件位置 确认所有必需的静态/动态链接库均已存在于当前工作区内的适当子文件夹之中,并且它们已被纳入至Linker Settings下的Library Files列表里。 ```plaintext Project -> Properties -> C/C++ Build -> Settings -> TI Linker -> Library files ``` #### 添加遗漏的关键模块 仔细核查是否有任何重要的实现单元尚未导入工程项目结构之内。特别是像"DSP2833x_MemCopy.c"这样的基础功能部件应当显式声明并关联起来以便顺利完成整个应用程序的整体组装流程。 #### 调整制作镜像的具体指令序列 对于涉及外部固件映射创建的操作而言,确保所使用的各项开关以及输入输出数据形式均严格匹配实际硬件平台的需求是非常关键的一环。下面给出了一条标准样例供参考对比之用: ```bash ./mkimage -A arm -O U-Boot -C none -T script -d debrick-nand.txt debrick.scr ``` > **注意**: 上述例子适用于特定类型的启动加载程序环境定制场景, 用户需依据自身具体情况做出相应调整. --- ### 总结说明 综上所述,当遭遇类似于无法定位某个具体资源之类的状况时,可以从三个方面入手排查即验证资源配置准确性、补充潜在丢失的部分以及优化自动化生产环节的各项细节处理方式从而达到彻底消除此类技术难题的目的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值