java 从零手写实现 ReadWriteLock 读写锁( 二 )
<>();/*** volatile 引用 , 保证线程间的可见性+易变性** @since 0.0.2*/private final AtomicReference writeOwner = new AtomicReference<>();/*** 写次数统计*/private int writeCount = 0;}获取读锁/** * 获取读锁,读锁在写锁不存在的时候才能获取 * * @since 0.0.2 */@Overridepublic synchronized void lockRead() {try {// 写锁存在,需要waitwhile (!tryLockRead()) {log.debug("获取读锁失败 , 进入等待状态 。 ");wait();}} catch (InterruptedException e) {Thread.interrupted();}}/** * 尝试获取读锁 * * 读锁之间是不互斥的 , 这里后续需要优化 。* * @return 是否成功 * @since 0.0.2 */private boolean tryLockRead() {if (writeCount > 0) {log.debug("当前有写锁 , 获取读锁失败");return false;}Thread currentThread = Thread.currentThread();// 次数暂时固定为1 , 后面如果实现可重入 , 这里可以改进 。this.readCountMap.put(currentThread, 1);return true;}
每次尝试获取读锁的时候 , 我们都将当前线程作为 key 放入 readCountMap 中 , 对应的值暂时为1 。
释放读锁释放读锁的时候 , 我们就会进行归属权校验 。
如果获取失败 , 则说明不是当前锁的持有者 , 则直接释放失败 。
/** * 释放读锁 * * @since 0.0.2 */@Overridepublic synchronized void unlockRead() {Thread currentThread = Thread.currentThread();Integer readCount = readCountMap.get(currentThread);if (readCount == null) {throw new RuntimeException("当前线程未持有任何读锁 , 释放锁失败!");} else {log.debug("释放读锁 , 唤醒所有等待线程 。 ");readCountMap.remove(currentThread);notifyAll();}}
获取写锁/** * 获取写锁 * * @since 0.0.2 */@Overridepublic synchronized void lockWrite() {try {// 写锁存在,需要waitwhile (!tryLockWrite()) {wait();}// 此时已经不存在获取写锁的线程了,因此占坑,防止写锁饥饿writeCount++;} catch (InterruptedException e) {Thread.interrupted();}}/** * 尝试获取写锁 * * @return 是否成功 * @since 0.0.2 */private boolean tryLockWrite() {if (writeCount > 0) {log.debug("当前有其他写锁 , 获取写锁失败");return false;}// 读锁if (!readCountMap.isEmpty()) {log.debug("当前有其他读锁 , 获取写锁失败 。 ");return false;}Thread currentThread = Thread.currentThread();boolean result = writeOwner.compareAndSet(null, currentThread);log.debug("尝试获取写锁结果:{}", result);return result;}
尝试获取写锁时 , 判断是否有写的条件不变 。
如果 readCountMap 不为空 , 则说明存在写锁 。
通过 CAS 设置对应的写线程持有信息 , 返回是否设置成功 。
释放写锁释放写锁的逻辑和原来类似 , 只不过添加了一个 owner 持有权的校验 。
/** * 释放写锁 * * @since 0.0.2 */@Overridepublic synchronized void unlockWrite() {boolean toNullResult = writeOwner.compareAndSet(Thread.currentThread(), null);if (toNullResult) {writeCount--;log.debug("写锁释放 , 唤醒所有等待线程 。 ");notifyAll();} else {throw new RuntimeException("释放写锁失败");}}
可重入的支持说明我们上一小节实现了一个支持验证锁持有者的读写锁 。
下面来看一下如何实现一个可重入的读写锁 。
类定义/** * 读写锁实现-可重入锁 * * @author binbin.hou * @since 0.0.2 */public class LockReadWriteRe implements IReadWriteLock {private static final Log log = LogFactory.getLog(LockReadWriteRe.class);/*** 如果使用类似 write 的方式 , 会导致读锁只能有一个 。* 调整为使用 HashMap 存放读的信息** @since 0.0.2*/private final Map readCountMap = new HashMap<>();/*** volatile 引用 , 保证线程间的可见性+易变性** @since 0.0.2*/private final AtomicReference writeOwner = new AtomicReference<>();/*** 写次数统计*/private int writeCount = 0;}
基本的属性和上一小节是一样的 。
获取读锁/** * 获取读锁,读锁在写锁不存在的时候才能获取 * * @since 0.0.2 */@Overridepublic synchronized void lockRead() {try {// 写锁存在,需要waitwhile (!tryLockRead()) {log.debug("获取读锁失败 , 进入等待状态 。 ");wait();}} catch (InterruptedException e) {Thread.interrupted();}}/** * 尝试获取读锁 * * 读锁之间是不互斥的 , 这里后续需要优化 。** @return 是否成功 * @since 0.0.2 */private boolean tryLockRead() {if (writeCount > 0) {log.debug("当前有写锁 , 获取读锁失败");return false;}Thread currentThread = Thread.currentThread();Integer count = readCountMap.get(currentThread);if(count == null) {count = 0;}// 可重入实现count++;this.readCountMap.put(currentThread, count);return true;}
这里和以前的区别就是支持可重入 , 通过 count 来维护每一个线程对应的读总数 。
释放读锁/** * 释放读锁 * * @since 0.0.2 */@Overridepublic synchronized void unlockRead() {Thread currentThread = Thread.currentThread();Integer readCount = readCountMap.get(currentThread);if (readCount == null) {throw new RuntimeException("当前线程未持有任何读锁 , 释放锁失败!");} else {readCount--;// 已经是最后一次if(readCount == 0) {readCountMap.remove(currentThread);} else {readCountMap.put(currentThread, readCount);}log.debug("释放读锁 , 唤醒所有等待线程 。 ");notifyAll();}}
- 零部件|马瑞利发力电动产品,全球第七大零部件供应商在转型
- 互联网|苏宁跳出“零售商”重组互联网平台业务 融资60亿只是第一步
- 王文鉴|从工人到千亿掌门人,征服华为三星,只因他36年只坚持做一件事
- 同轴心配合|用SolidWorks画一个直角传动,画四个零件就行
- 现状|程序员现状揭秘:平均年薪20.36万,Java人才需求量最大
- 精英|业务流程图怎么绘制?销售精英的经验之谈
- 走向|电商,从货架陈列走向内容驱动
- 权属|从数据悖论到权属确认,数据共享进路所在
- 高配版|从4599元跌至3699元,256GB+65W,12GB旗舰加速退场
- 科技|联咏科技将从明年下半年开始为iPad提供LCD驱动芯片