想到读写锁,大家第一时间想到的可能是ReentrantReadWriteLock。实际上,在jdk8以后,java提供了一个性能更优越的读写锁并发类StampedLock,该类的设计初衷是作为一个内部工具类,用于辅助开发其它线程安全组件,用得好,该类可以提升系统性能,用不好,容易产生死锁和其它莫名其妙的问题。本文主要和大家一起学习下StampedLock的功能和使用。,StampedLock的状态由版本和模式组成。锁获取方法返回一个戳,该戳表示并控制对锁状态的访问。StampedLock提供了3种模式控制访问锁:,获取写锁,它是独占的,当锁处于写模式时,无法获得读锁,所有乐观读验证都将失败。,悲观的方式后去非独占读锁。,乐观读也就是若读的操作很多,写的操作很少的情况下,你可以乐观地认为,写入与读取同时发生几率很少,因此不悲观地使用完全的读取锁定,程序可以查看读取资料之后,是否遭到写入执行的变更,再采取后续的措施(重新读取变更信息,或者抛出异常) ,这一个小小改进,可大幅度提高程序的吞吐量。,StampedLock支持 tryOptimisticRead()方法,读取完毕后做一次戳校验,如果校验通过,表示这期间没有其他线程的写操作,数据可以安全使用,如果校验没通过,需要重新获取读锁,保证数据一致性。,此外,StampedLock 提供了api实现上面3种方式进行转换:,如果锁状态与给定的戳记匹配,则执行以下操作之一。如果戳记表示持有写锁,则返回它。或者,如果是读锁,如果写锁可用,则释放读锁并返回写戳记。或者,如果是乐观读,则仅在立即可用时返回写戳记。该方法在所有其他情况下返回零,如果锁状态与给定的戳记匹配,则执行以下操作之一。如果戳记表示持有写锁,则释放它并获得读锁。或者,如果是读锁,返回它。或者,如果是乐观读,则仅在立即可用时才获得读锁并返回读戳记。该方法在所有其他情况下返回零。,如果锁状态与给定的戳记匹配,那么如果戳记表示持有锁,则释放它并返回一个观察戳记。或者,如果是乐观读,则在验证后返回它。该方法在所有其他情况下返回0,因此作为“tryUnlock”的形式可能很有用。,下面用一个例子演示下StampedLock的使用,例子来源jdk中的javadoc。,测试用例:,结果:,,正是由于StampedLock的乐观读模式,早就StampedLock的高性能和高吞吐量,那么具体的性能提高有多少呢?,下图是和ReadWritLock相比,在一个线程情况下,读速度是其4倍左右,写是1倍。,,下图是16个线程情况下,读性能是其几十倍,写性能也是近10倍左右:,,下图是吞吐量提高:,,那么这样是不是说StampedLock可以全方位的替代ReentrantReadWriteLock, 答案是否定的,StampedLock相对于ReentrantReadWriteLock有下面两个问题:,所以最终选择StampedLock还是ReentrantReadWriteLock,还是要看具体的业务场景。,本文主要讲解了StampedLock的功能和使用,至于原理,StampedLock虽然不像其它锁一样定义了内部类来实现AQS框架,但是StampedLock的基本实现思路还是利用CLH队列进行线程的管理,通过同步状态值来表示锁的状态和类型,具体的源码实现大家感兴趣的自己可以追踪看看。
文章版权声明
1 原创文章作者:cmcc,如若转载,请注明出处: https://www.52hwl.com/16577.html
2 温馨提示:软件侵权请联系469472785#qq.com(三天内删除相关链接)资源失效请留言反馈
3 下载提示:如遇蓝奏云无法访问,请修改lanzous(把s修改成x)
4 免责声明:本站为个人博客,所有软件信息均来自网络 修改版软件,加群广告提示为修改者自留,非本站信息,注意鉴别