java读写锁死锁例子_Java 读写锁 ReentrantReadWriteLock 源码分析

本文介绍了Java ReentrantReadWriteLock的使用,通过一个缓存操作的例子展示了如何避免死锁,并深入探讨了锁的内部结构。ReentrantReadWriteLock分为读锁和写锁,读锁可共享,写锁独占。锁的实现基于AQS,通过共享模式和独占模式管理状态,高16位和低16位分别对应读写操作。
摘要由CSDN通过智能技术生成

下面这个例子非常实用,我是 javadoc 的搬运工:

// 这是一个关于缓存操作的故事

classCachedData{

Object data;

volatileboolean cacheValid;

// 读写锁实例

final ReentrantReadWriteLock rwl =newReentrantReadWriteLock();

voidprocessCachedData(){

// 获取读锁

rwl.readLock().lock();

if(!cacheValid) {// 如果缓存过期了,或者为 null

// 释放掉读锁,然后获取写锁 (后面会看到,没释放掉读锁就获取写锁,会发生死锁情况)

rwl.readLock().unlock();

rwl.writeLock().lock();

try{

if(!cacheValid) {// 重新判断,因为在等待写锁的过程中,可能前面有其他写线程执行过了

data = ...

cacheValid =true;

}

// 获取读锁 (持有写锁的情况下,是允许获取读锁的,称为 “锁降级”,反之不行。)

rwl.readLock().lock();

}finally{

// 释放写锁,此时还剩一个读锁

rwl.writeLock().unlock();// Unlock write, still hold read

}

}

try{

use(data);

}finally{

// 释放读锁

rwl.readLock().unlock();

}

}

}

ReentrantReadWriteLock 分为读锁和写锁两个实例,读锁是共享锁,可被多个线程同时使用,写锁是独占锁。持有写锁的线程可以继续获取读锁,反之不行。

这一节比较重要,我们要先看清楚 ReentrantReadWriteLock 的大框架,然后再到源码细节。

首先,我们来看下 ReentrantReadWriteLock 的结构,它有好些嵌套类:

AAffA0nNPuCLAAAAAElFTkSuQmCC

大家先仔细看看这张图中的信息。然后我们把 ReadLock 和 WriteLock 的代码提出来一起看,清晰一些:

AAffA0nNPuCLAAAAAElFTkSuQmCC

很清楚了,ReadLock 和 WriteLock 中的方法都是通过 Sync 这个类来实现的。Sync 是 AQS 的子类,然后再派生了公平模式和不公平模式。

从它们调用的 Sync 方法,我们可以看到:ReadLock 使用了共享模式,WriteLock 使用了独占模式。

等等,同一个 AQS 实例怎么可以同时使用共享模式和独占模式???

这里给大家回顾下 AQS,我们横向对比下 AQS 的共享模式和独占模式:

AAffA0nNPuCLAAAAAElFTkSuQmCC

AQS 的精髓在于内部的属性state:

对于独占模式来说,通常就是 0 代表可获取锁,1 代表锁被别人获取了,重入例外

而共享模式下,每个线程都可以对 state 进行加减操作

也就是说,独占模式和共享模式对于 state 的操作完全不一样,那读写锁 ReentrantReadWriteLock 中是怎么使用 state 的呢?答案是将 state 这个 32 位的 int 值分为高 16 位和低 16位,分别用于共享模式和独占模式。

作者:慕容千语

链接:https://www.jianshu.com/p/27ac83f340c4

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值