死磕到底-深入理解ReentrantReadWriteLock源码
2021/10/20 14:09:54
本文主要是介绍死磕到底-深入理解ReentrantReadWriteLock源码,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
1.线程安全
、
如果对num进行累加操作,使用10个线程,每个加1000次,最后应该是10000,但是你会发现不是10000。
当使用了synchronized再次进行累加操作。此时累加的值就是10000,这是因为synchronized能够保证每次只有一个线程进入临界区。
2.ReentrantReadWriteLock
、
JDK中synchronized的使用是非常广泛的,例如线程安全的HashTable,HashTable保证线程安全就是在每个方法上都加上了synchronized。如下是HashTable的put和get方法。
对于HashTable来说,你发没发现一个问题就是实际上我们多个线程调用get方法的时候并不需要加锁,原因是如果不存在更改HashTable结构的操作,这样只是调用get方法但是加了synchronized。在多线程情况下并发度会大大降低。
那么有没有一种锁可以在读的时候不加锁,写的时候才加锁。同时写和写是冲突的,读和写也是冲突的,但是读和读是不会冲突的。这就是读写锁
ReentrantReadWriteLock。可以通过下面的例子看到实际上故意注释了解锁的unlock,所有的读锁还是能够进行获取资源。
写和读之间冲突,只有释放了写锁,读锁才能获取资源。下面代码只是方便演示,实际上解锁必须放在finally中,防止因为异常没有释放锁。其他线程阻塞的问题。
同样写和写也是冲突的,只有等写锁释放了其他线程才能够拿到写锁。
3.源码
读锁的lock源码
同首先调用lock会调用acquireShared方法,而acquireShared方法中调用了tryAcquireShared(尝试获取锁),只要获取成功了就返回1否则-1,也就是说只有获取锁失败才会执行doAcquireShared。
tryAcquireShared实现如下,需要注意的是读写锁采用了state来表示状态,高16位表示读状态数量,低16位表示写状态数量。
只要获取成功就会返回1也就是不会执行doAcquireShared,也只有获取失败才会执行doAcquireShared。doAcquireShared的基本实现如下。和之前说的ReentrantLock一样,读写锁会把需要阻塞的线程放入队列中。然后当可以获取锁的时候再进行唤醒操作。
读锁的unLock源码
首先调用releaseShared方法,然后releaseShared调用了tryReleaseShared方法,只有tryReleaseShared返回为true才会调用doReleaseShared方法,同时tryReleaseShared返回true表示锁已经释放完毕,包括重入的锁。
tryReleaseShared的实现如下,可以看到只有nextc == 0的时候也就是所有读线程已经释放完毕的时候才会返回true。
doReleaseShared可能你也猜到了需要干嘛,对于阻塞的线程我们都放在队列中,既然锁都释放完毕了那么肯定是唤醒他们。doReleaseShared实现如下。
到此在读锁到源码已经说完了,接下来就是写锁的源码
写锁的lock源码
写锁的lock首先调用acquire方法
acquire方法只有拿到锁或者重入成功后才会返回ture,也就是只有没有拿到锁或者没有重入成功才会执行才会执行acquireQueued(addWaiter(Node.EXCLUSIVE), arg)方法进行加入队列以及阻塞线程。
tryAcquire方法实现如下所示,可以看到只有重入成功或者加锁成功的时候才会返回true。
一旦加锁或者重入失败此时会先调用addWaiter方法加入等待队列中
加入队列后那么肯定是要阻塞线程,此时会调用acquireQueued方法,然后尝试再次获取锁,一旦失败会阻塞线程。
到此写锁的加锁源码结束。接下来是解锁过程。
写锁的unLock源码
到此写锁的加锁源码结束。接下来是解锁过程。解锁会先调用release方法,然后release方法会调用release方法。
通过tryRelease方法可以看到只有所有的写锁都释放完毕了才会进行唤醒,也就是调用exclusiceCount的时候等于0。一旦释放完毕此时release中会拿到头部节点然后唤醒队列头部的线程,此时你可能在想那写锁只是唤醒了头部获取读锁被阻塞的有多个,这些是怎么被唤醒的呢?实际上在读锁被阻塞中调用了doAcquireShared方法,一旦被释放,此时会将除了头部以外后续的节点都唤醒。
这篇关于死磕到底-深入理解ReentrantReadWriteLock源码的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-06-26终极指南:Scrum中如何设置需求优先级
- 2024-06-26AI大模型企业应用实战(25)-为Langchain Agent添加记忆功能
- 2024-06-26小白家庭 nas 搭建方案-icode9专业技术文章分享
- 2024-06-23AI大模型企业应用实战(14)-langchain的Embedding
- 2024-06-23AI大模型企业应用实战(15)-langchain核心组件
- 2024-06-23AI大模型企业应用实战(16)-langchain核心组件
- 2024-06-23AI 大模型企业应用实战(06)-初识LangChain
- 2024-06-19EntBot.ai: AI Website Chatbot for Product Guides and Development Doc
- 2024-06-17zero-shot-learning-definition-examples-comparison
- 2024-06-06Package Easy(基于 NSIS 的打包exe安装包工具)使用方法-icode9专业技术文章分享