可以看到,上述示例最特殊的其实是distanceFromOrigin方法,这个方法中使用了“Optimistic reading”乐观读锁,使得读写可以并发执行,但是“Optimistic reading”的使用必须遵循以下模式:
long stamp = lock.tryOptimisticRead(); // 非阻塞获取版本信息copyVaraibale2ThreadMemory(); // 拷贝变量到线程本地堆栈if(!lock.validate(stamp)){ // 校验 long stamp = lock.readLock(); // 获取读锁 try { copyVaraibale2ThreadMemory(); // 拷贝变量到线程本地堆栈 } finally { lock.unlock(stamp); // 释放悲观锁 }}useThreadMemoryVarables(); // 使用线程本地堆栈里面的数据进行操作
三、StampedLock原理3.1 StampedLock的内部常量StampedLock虽然不像其它锁一样定义了内部类来实现AQS框架,但是StampedLock的基本实现思路还是利用CLH队列进行线程的管理,通过同步状态值来表示锁的状态和类型 。
StampedLock内部定义了很多常量,定义这些常量的根本目的还是和ReentrantReadWriteLock一样,对同步状态值按位切分,以通过位运算对State进行操作:
对于StampedLock来说,写锁被占用的标志是第8位为1,读锁使用0-7位,正常情况下读锁数目为1-126,超过126时,使用一个名为readerOverflow的int整型保存超出数 。
// 用于计算state值的位常量private static final int LG_READERS = 7;private static final long RUNIT = 1L; // 一单位读锁 0000 0001private static final long WBIT = 1L << LG_READERS; // 写锁标志位 1000 0000private static final long RBITS = WBIT - 1L; // 读状态标志 0111 1111private static final long RFULL = RBITS - 1L; // 读锁的最大数量 0111 1110private static final long ABITS = RBITS | WBIT; // 用于获取读写状态 1111 1111private static final long SBITS = ~RBITS; // 1111...1000 0000/** * 初始state值*/private static final long ORIGIN = WBIT << 1;/** * 同步状态state,处于写锁使用第8位(为1表示占用),读锁使用前7位(为1~126,附加的readerOverflow用于当读锁超过126时)*/private transient volatile long state;/** * 因为读锁只使用了前7位,所以当超过对应数值之后需要使用一个int型保存 */private transient int readerOverflow;
部分常量的比特位表示如下:文章插图
另外,StampedLock相比ReentrantReadWriteLock,对多核CPU进行了优化,可以看到,当CPU核数超过1时,会有一些自旋操作:
/*** CPU核数,用于控制自旋次数*/private static final int NCPU = Runtime.getRuntime().availableProcessors();/** * 尝试获取锁时,如果超过该值仍未获取到锁,则进入等待队列*/private static final int SPINS = (NCPU > 1) ? 1 << 6 : 0;/** * 等待队列的首节点,自旋获取锁失败时会,会继续阻塞*/private static final int HEAD_SPINS = (NCPU > 1) ? 1 << 10 : 0;/** * 再次进入阻塞之前的最大重试次数*/private static final int MAX_HEAD_SPINS = (NCPU > 1) ? 1 << 16 : 0;
3.2 示例分析假设现在有三个线程:ThreadA、ThreadB、ThreadC、ThreadD 。操作如下:1. StampedLock对象的创建StampedLock的构造器很简单,构造时设置下同步状态值:
// ThreadA调用writeLock, 获取写锁
// ThreadB调用readLock, 获取读锁
// ThreadC调用readLock, 获取读锁
// ThreadD调用writeLock, 获取写锁
// ThreadE调用readLock, 获取读锁
推荐阅读
- 好壶难得知己更难求,茶具知识什么是花器
- 比宇宙更古老的恒星 宇宙最古老的恒星
- 漂亮的女人离婚概率更大是为什么?
- 经常喝茶好吗,如何品茶会更健康
- 据说“新陈代谢”快的人更健康!用运动来为代谢“加速”
- 冬天严寒手脚干裂 护手霜使用不当副作用更大
- 冬季泡脚要加四样宝 养生效果会更好
- Android端微软远程桌面应用更新:全面支持Windows虚拟桌面
- 饮食|更适合老年人的饮食结构是什么?
- 失眠吃什么好 治疗更年期失眠的六款药膳粥