[TOC]
一、读写锁
在我的《java并发编程》上一篇文章中为大家介绍了《ReentrantLock读写锁》,ReentrantReadWriteLock能够保障最多同时有一个线程在写数据,或者能够同时有多个线程读数据,但读写不能同时进行。
比方你正在做的是日志,有一个线程正在做写操作,然而在写日志的时候你可能须要把日志集中转移到集中管理日志服务,然而此时读线程不能读数据(因为无奈获取读锁)。面对这个需要,ReentrantReadWriteLock显然不是咱们的解决方案,咱们心愿:最多一个线程在进行写操作(加写锁),然而同时容许多个线程进行读操作(加读锁),解决方案是StampedLock。
二、乐观读锁
StampedLock 同样能够实现写锁和读锁的性能,Stamped在英文中有印章的含意,对于StampedLock大家能够这么了解,应用一个印章加锁,必须应用该印章解锁。
public class TestStampedLock { Map<String,String> map = new HashMap<>(); //锁对象 private StampedLock lock = new StampedLock(); //写操作函数 public void put(String key, String value){ long stamp = lock.writeLock(); //加写锁 try { map.put(key, value); //写操作 } finally { lock.unlockWrite(stamp); //开释写锁 } } public String get(String key) { long stamp = lock.readLock(); //加读锁 try { return map.get(key); //读操作 } finally { lock.unlockRead(stamp); //开释读锁 } }}
上文中的读锁readLock,在StampedLock模式中被称为乐观读锁,之所以叫做乐观读锁是和StampedLock反对的另一种模式“乐观读”绝对应的。
写锁、乐观读锁的语义和 ReadWriteLock 的写锁、读锁的语义根本是统一的,容许多个线程同时获取乐观读锁,然而只容许一个线程获取写锁,写锁和乐观读锁是互斥的。多线程环境下,写操作的同时不能读。所以到这里为止,StampedLock与ReadWriteLock并没有很大的区别。
三、乐观读
须要留神的是,这里我写的是乐观读,而不是乐观读锁,因为乐观读是不加锁的。通过tryOptimisticRead()函数获取一个stamp,这里的tryOptimisticRead() 就是乐观读,乐观读因为没有加锁,所以读取数据的性能会更高一点。即:曾经有写操作线程加锁的同时,依然容许读操作线程持续进行。
如果你的读写操作有比拟强的工夫点数据一致性要求,即:同一个工夫点读操作读到的数据,肯定与该工夫点写操作保持数据一致性。那么,你就须要进行validate校验,stamp此时能够了解为一个版本号,如果写操作版本为2,读操作版本为1,阐明你读到的数据不是最新的。你须要去读取最新版本的数据(版本号为2),所以须要降级为乐观读锁,代码如下:
public String readWithOptimisticLock(String key) { long stamp = lock.tryOptimisticRead(); //乐观读 String value = map.get(key); //读取数据 if(!lock.validate(stamp)) { //校验数据是否是最新版本 stamp = lock.readLock(); //如果不是,降级为乐观读锁 try { return map.get(key); } finally { lock.unlock(stamp); } } return value;}
欢送关注我的博客,更多精品常识合集
本文转载注明出处(必须带连贯,不能只转文字):字母哥博客 - zimug.com
感觉对您有帮忙的话,帮我点赞、分享!您的反对是我不竭的创作能源!。另外,笔者最近一段时间输入了如下的精品内容,期待您的关注。
- 《kafka修炼之道》
- 《手摸手教你学Spring Boot2.0》
- 《Spring Security-JWT-OAuth2一本通》
- 《实战前后端拆散RBAC权限管理系统》
- 《实战SpringCloud微服务从青铜到王者》