国外mod大型网站,加盟餐饮的网站建设,常见网页制作软件,程序开发是干什么的文章目录 1、邮戳锁2、锁饥饿问题的解决思路3、邮戳锁的特点4、代码演示#xff1a;邮戳锁的传统读写用法5、代码演示#xff1a;邮戳锁之乐观读6、邮戳锁的缺点7、终章回顾 前面提到了从无锁 ⇒ 独占锁 ⇒ 读写锁#xff0c;但读写锁存在写锁饥饿的情况。 #x1f4d5;【读… 文章目录 1、邮戳锁2、锁饥饿问题的解决思路3、邮戳锁的特点4、代码演示邮戳锁的传统读写用法5、代码演示邮戳锁之乐观读6、邮戳锁的缺点7、终章回顾 前面提到了从无锁 ⇒ 独占锁 ⇒ 读写锁但读写锁存在写锁饥饿的情况。 【读写锁的演化与锁降级】
本篇邮戳锁也称版本锁、票据锁即是对读写锁的再一次演化。
1、邮戳锁 StampedLock是JDK1.8中新增的一个读写锁也是对JDK1.5中的读写锁ReentrantReadWriteLock的优化。 stamp戳记long类型代表了锁的状态当stamp返回0时表示线程获取锁失败且当释放锁或者转换锁时都要传入最初获取的stamp值。
2、锁饥饿问题的解决思路
idea1使用公平锁可一定程度上缓解锁饥饿问题但这样是以牺牲系统吞吐量为代价的new ReentrantReadWriteLock(true);
idea2Java8的StampedLock类的乐观读锁读写锁的实现类ReentrantReadWriteLock是读写互斥写写互斥但读读共享因此性能比synchronized等独占锁好很多。而其读写互斥的特点在读线程多写线程少时会导致写锁饥饿基于此邮戳锁提供乐观锁。
获取乐观锁后其他线程尝试获取写锁时不再会被阻塞同时乐观读后也要对结果进行校验。很乐观认为我读的时候不会有人改如此相比ReentrantReadWriteLock读写锁性能又上了一个台阶。 对短的只读代码段使用乐观模式通常可以减少争用并提高吞吐量 强调短的读是因为读的时间短了中间被写线程改数据的概率就低更容易乐观成功 3、邮戳锁的特点
所有获取锁的方法都返回一个邮戳StampStamp为零表示锁获取失败其余都表示成功所有释放锁的方法都需要一个邮戳Stamp这个Stamp必须是和成功获取锁时得到的stamp一致StampedLock是不可重入的因此如果一个线程已经持有了写锁又再去获取写锁的话就会造成死锁
StampedLock有三种访问模式
Reading(读模式悲观)功能和ReentrantReadWriteLock的读锁类似Writing(写模式)功能和ReentrantRerdWriteLock的写锁类似Optimistic reading (乐观读模式)无锁机制类似于数据库中的乐观锁支持读写并发很乐观的认为读取时没人修改假如被修改再升级为悲观读模式
4、代码演示邮戳锁的传统读写用法
以下演示邮戳锁也可以当作传统的读写锁来使用
//资源类
public class ShareSource {int number 6;StampedLock stampedLock new StampedLock();/*** 写*/public void writer(){long stamp stampedLock.writeLock();System.out.println(Thread.currentThread().getName() 写线程准备修改共享资源);try{number number 1;}finally {stampedLock.unlockWrite(stamp);}System.out.println(Thread.currentThread().getName() 写线程修改结束);}/*** 悲观读没读完时写锁无法获取* 读的过程中停几秒以明显看到是否允许写锁进入*/public void read(){long stamp stampedLock.readLock();System.out.println(Thread.currentThread().getName() 进入读锁预计4秒后读取完成);for (int i 1; i 5; i) {try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) {e.printStackTrace();}NumberFormat nf NumberFormat.getPercentInstance();nf.setMaximumFractionDigits(2); //最大小数位数System.out.println(Thread.currentThread().getName() 读取进度 nf.format(i/4.00));}try{int result number;System.out.println(Thread.currentThread().getName() 读取完成获得共享对象变量值为 result);}finally {stampedLock.unlockRead(stamp);}}
}
测试类
public class Test {public static void main(String[] args) throws InterruptedException {ShareSource shareSource new ShareSource();new Thread(() - {shareSource.read();}, readThread).start();//为了测试效果确保读线程先启动TimeUnit.MILLISECONDS.sleep(100);new Thread(() - {shareSource.writer();}, writeThread).start();//这里不用JUC辅助类了直接sleep等着TimeUnit.SECONDS.sleep(6);System.out.println(Thread.currentThread().getName() 查看最终结果number: shareSource.number);}
}运行和普通的读写锁没什么区别没读完前写线程不让进依旧读写互斥 5、代码演示邮戳锁之乐观读
下面用邮戳锁的乐观读演示读的过程也允许写锁介入。先看乐观读的校验方法
//返回true代表中途没被其他线程修改public boolean validate(long stamp)Demo修改写资源类的乐观读的业务方法
//资源类
/*** 乐观读* 读的过程中允许写锁的获取*/
public void optimisticRead(){long stamp stampedLock.tryOptimisticRead();int result number;//故意间隔4秒看中间有没其他线程修改过numberfor (int i 1; i 5; i) {try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() 正在读取中 i 秒后validate方法值true无修改false有修改 stampedLock.validate(stamp));}//读完了校验下中途有没被写线程修改过若有则升级为悲观读重读若无则无锁偷鸡成功if (!stampedLock.validate(stamp)){System.out.println(中途被写线程修改过);stamp stampedLock.readLock();try {System.out.println(已从乐观读升级为悲观读.......);result number;System.out.println(悲观读重读的结果 result);} finally {stampedLock.unlockRead(stamp);}}//最终结果System.out.println(final result: result);
}测试类同上启动两个线程充当读线程和写线程 再调6妙后写线程介入发现乐观读偷鸡成功 6、邮戳锁的缺点
StampedLock 不支持重入没有Re开头StampedLock 的悲观读锁和写锁都不支持条件变量 (Condition)使用stampedLock一定不要调用中断操作即不要调用interrupt()方法
7、终章回顾
到此JUC课程整理完成。2023/12/21 10:54画个xmind图整体梳理一遍 顺畅多了舒服了。之前课完结最后一篇笔记整理完直接走人这次按课程老师说的串一遍不错的习惯。