ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

话说 ReadWriteLock

2021-04-17 15:03:43  阅读:174  来源: 互联网

标签:rw Thread ReadWriteLock test new rh public


ReadWriteLock

读写锁:读读不互斥,读写互斥,写写互斥;

也就是说:

A读的时候B可以读,

A读的时候B不可以写,

A写的时候B不可以写

这里举个例子:不同线程对变量x 读 写

public class ReadWriteLockTest {ReadWriteLock rw = new ReentrantReadWriteLock();public int x = 0;public static void main(String[] args) {}// A读public void A(){try{// 读锁rw.readLock().lock();System.out.println("A开始读: x="+x);sleep(5);System.out.println("A读完了: x="+x);} catch (Exception e) {e.printStackTrace();}finally {rw.readLock().unlock();}}// B读public void B(){try{// 读锁rw.readLock().lock();System.out.println("B开始读: x="+x);sleep(5);System.out.println("B读完了: x="+x);} catch (Exception e) {e.printStackTrace();}finally {rw.readLock().unlock();}}// C写public void C(){try{// 写锁rw.writeLock().lock();System.out.println("C开始写: x="+x);sleep(5);x = 10;System.out.println("C写完了: x="+x);} catch (Exception e) {e.printStackTrace();}finally {rw.writeLock().unlock();}} // D写public void D(){try{// 写锁rw.writeLock().lock();System.out.println("D开始写: x="+x);sleep(5);x = 100;System.out.println("D写完了: x="+x);} catch (Exception e) {e.printStackTrace();}finally {rw.writeLock().unlock();}}// E 同一线程 读写不互斥public void E(){try{// 写锁rw.writeLock().lock();System.out.println("E开始写: x="+x);x = 99;rw.readLock().lock();System.out.println("E没写完呢 E开始读:x="+x);x = 100;System.out.println("E写完了: x="+x);} catch (Exception e) {e.printStackTrace();}finally {rw.writeLock().unlock();}}// 睡眠指定秒public void sleep(int s){try {Thread.sleep(s*1000);} catch (Exception e){e.printStackTrace();}}}

1. A 读 B可读 读读共享

 public static void main(String[] args) { ReadWriteLockTest test = new ReadWriteLockTest(); new Thread(test::A).start(); new Thread(test::B).start();
 }输出结果:
A开始读: x=0B开始读: x=0B读完了: x=0A读完了: x=0

2. A 读 C 不可写 读写互斥

public static void main(String[] args) {ReadWriteLockTest test = new ReadWriteLockTest();new Thread(test::A).start();new Thread(test::C).start();}输出结果:
A开始读: x=0A读完了: x=0C开始写: x=0C写完了: x=10

3. B 写 A 不可读 读写互斥

public static void main(String[] args) {ReadWriteLockTest test = new ReadWriteLockTest();new Thread(test::C).start();new Thread(test::A).start();}输出结果:
C开始写: x=0C写完了: x=10A开始读: x=10A读完了: x=10

4. C写 D不可写 写写互斥

 public static void main(String[] args) {ReadWriteLockTest test = new ReadWriteLockTest();new Thread(test::C).start();new Thread(test::D).start();
 }输出结果:
C开始写: x=0C写完了: x=10D开始写: x=10D写完了: x=100

5. 线程自己读写不互斥

public static void main(String[] args) {ReadWriteLockTest test = new ReadWriteLockTest();new Thread(test::E).start();}

6. 总结

读读共享,读写互斥,写写互斥

可以把读比作是女生,把共享资源比作是厕所,女生跟女生可以拉手进厕所(读读),女生和男生不可以拉手进厕所(读写),男生和男生不可以拉手进厕所(写写)

7. 唠一唠实现方式

7.1 类继承关系

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

7.2 lock过程
ReadWriteLock rw = new ReentrantReadWriteLock();rw.readLock().lock();

读锁lock大体流程是这样的:

在这里插入图片描述

与ReentrantLock获取锁的过程基本一致,只是在tryAcquire(写锁) 与 tryReleaseShared(读锁) 的时候有些区别

前置知识:

读写锁是怎么用state标记是读锁(数量)还是写锁(数量)的 ,要是我设计这个代码,

我可能会用 int readState,int writeState , 两个单独的状态来标识读锁 (数量)和写锁(数量)

但是AQS 说了 只能用 一个state 和 一个双向队列 来 实现 (模板方法),你不能自己瞎给我改。

看看大佬们怎么实现的:

大佬把state切开了,int类型数据大小为4字节 32位 ,大佬把32分成了16+16 高16位表示共享锁,低16位表示独占锁
在这里插入图片描述

tryAcquireShared

protected final int tryAcquireShared(int unused) {// 获取当前线程 Thread current = Thread.currentThread();// 获取stateint c = getState();// 看一下是不是独占状态(写锁),如果是独占再看一下持有锁的线程是不是当前线程,如果不是返回-1 失败// 如果线程E获取了独占锁 他是可以再获取共享锁锁的 看5线程自己读写不互斥例子if (exclusiveCount(c) != 0 &&getExclusiveOwnerThread() != current)return -1;// 获取共享锁数量(高16位)int r = sharedCount(c);// 判断是不是需要blockif (!readerShouldBlock() &&// 判断获取锁的线程有没有超过最大线程r < MAX_COUNT && // cas设置state 这里不是c+1 是c+SHARED_UNIT // SHARED_UNIT的二进制位: 10000_0000_0000_0000 // 为什么是加这个 因为是高16位+1  也就是需要加65536=65535+1compareAndSetState(c, c + SHARED_UNIT)) {// 到这里其实已经获取锁成功了 下边的一些操作 是设置一些需要的属性if (r == 0) {// 如果是第一个独占锁 就设置firstReader为当前线程// firstReaderHoldCount = 1firstReader = current;firstReaderHoldCount = 1;} else if (firstReader == current) {// 如果第一个独享锁占有者是自己 那就firstReaderHoldCount++firstReaderHoldCount++;} else {// 第一个独占锁不是自己  这里操作骚里骚气 没有很懂// 只知道是把持有独占锁的次数+1(排除第一个获取独占锁的线程 因为上边那两个变量单独记录了)// 这里用到了threadlocal技术// cachedHoldCounter 这个玩意存着最后获取共享锁的线程 和 数量 HoldCounter rh = cachedHoldCounter;// if (rh == null || rh.tid != getThreadId(current))// readHolds.get()就是返回ThreadLocal中存储的对象 线程第一次进来会创建cachedHoldCounter = rh = readHolds.get();else if (rh.count == 0)readHolds.set(rh);// 独占锁总数+1 rh.count++;}return 1;}// 如果没有成功 调用fullTryAcquireSharedreturn fullTryAcquireShared(current);}

fullTryAcquireShared

 // 上边失败了 这里就死循环获取锁 final int fullTryAcquireShared(Thread current) {
    HoldCounter rh = null;for (;;) {// 获取stateint c = getState();// 跟上边一样 if (exclusiveCount(c) != 0) {if (getExclusiveOwnerThread() != current)return -1;// else we hold the exclusive lock; blocking here// would cause deadlock.// readerShouldBlock这个公平锁和非公平锁的逻辑不一样 } else if (readerShouldBlock()) {// Make sure we're not acquiring read lock reentrantlyif (firstReader == current) {// assert firstReaderHoldCount > 0;} else {if (rh == null) {rh = cachedHoldCounter;if (rh == null || rh.tid != getThreadId(current)) {rh = readHolds.get();if (rh.count == 0)readHolds.remove();}}if (rh.count == 0)return -1;}}// 最大获取锁线程数校验if (sharedCount(c) == MAX_COUNT)throw new Error("Maximum lock count exceeded");// +1 if (compareAndSetState(c, c + SHARED_UNIT)) {// 上边一样 一系列设置if (sharedCount(c) == 0) {firstReader = current;firstReaderHoldCount = 1;} else if (firstReader == current) {firstReaderHoldCount++;} else {if (rh == null)rh = cachedHoldCounter;if (rh == null || rh.tid != getThreadId(current))rh = readHolds.get();else if (rh.count == 0)readHolds.set(rh);rh.count++;cachedHoldCounter = rh; // cache for release}return 1;}}}

在这里插入图片描述


标签:rw,Thread,ReadWriteLock,test,new,rh,public
来源: https://blog.51cto.com/u_12198094/2713567

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有