1.java中的非公平锁不怕有的线程一直得不到执行吗
2.33张图解析ReentrantReadWriteLock源码
3.9.读写锁ReentrantReadWriteLock 的实现原理
4.读写锁ReadWriteLock的实现原理
java中的非公平锁不怕有的线程一直得不到执行吗
首先来看公平锁和非公平锁,我们默认使用的锁是非公平锁,只有当我们显示设置为公平锁的情况下,才会使用公平锁,下面我们简单看一下公平锁的源码,如果等待队列中没有节点在等待,孔云龙瀑布线指标源码则占有锁,如果已经存在等待节点,则返回失败,由后面的程序去将此线程加入等待队列通过上面的代码,我们可以推断,当使用公平锁的情况下,并且同一个线程的执行时间较长时,线程内部进行了多次的锁的获取和释放,效率非常低下,可以参加Lesson8中的demo:
demo Lesson8LockIntPerform:在使用ReentrantLock加非公平锁的情况下个线程循环下单数为:
demo Lesson8LockIntPerform:在使用ReentrantLock加非公平锁的情况下个线程循环下单数为:
demo Lesson8LockFairIntPerform:在使用ReentrantLock加公平锁的情况下个线程循环下单数为:
demo Lesson8LockFairIntPerform:在使用ReentrantLock加公平锁的情况下个线程循环下单数为:
上面的demo中,在使用公平锁的情况下性能明显降低,非公平锁的性能是公平锁性能的几十倍以上,这和公平锁每次试图占有锁时,都必须先要进等待队列,按照FIFO的顺序去获取锁,因此在我们的cmake源码解读实验情景下,使用公平锁的线程进行了频繁切换,而频繁切换线程,性能必然会下降的厉害,这也告诫了我们在实际的开发过程中,在需要使用公平锁的情景下,务必要考虑线程的切换频率。
接下来我们来看一下读写锁,通过看读写锁的实现源码,我们可以发现,读锁和写锁共用同一个等待队列,那么在采用非公平锁的情况下,如果读锁的线程执行时间比较长,并且读锁的并发比较高,那么写锁的线程便永远都拿不到锁,那么实际的情况会不会是这样呢?
demo Lesson3WriteReadLock:此demo的读线程在不断的占用读锁,按照推论,写锁的线程是没有机会获取到锁的,但是实际情况是写锁的线程可以正常的获取到锁,那么是什么原因使得写锁的线程可以获取到锁的了?通过查看源代码,会发现有这样的一个方法:
上面的方法,实现了一个新的wincc程序源码读线程获取锁的中断,它会读取等待队列中下一个等待锁的线程,如果它是获取写锁的线程,那么此方法返回为真,调用它的程序会把这个试图获取读锁的线程加入到等待队列,从而终止了读线程一直都在占有锁的情况。
张图解析ReentrantReadWriteLock源码
今天,我们深入探讨ReentrantReadWriteLock源码,解析其内部结构与工作原理。文章分为多个部分,逐一剖析读写锁的创建、获取与释放过程。读写锁规范与实现
ReentrantReadWriteLock(简称RRW)作为读写锁,其核心功能在于控制并发访问的读与写操作。为了规范读写锁的使用,RRW首先声明了ReadWriteLock接口,并通过ReadLock与WriteLock实现接口,确保读锁与写锁的正确操作。 为了实现锁的基本功能,WriteLock与ReadLock都继承了Lock接口。这些类内部依赖于AQS(AbstractQueuedSynchronizer)抽象类,AQS为加锁和解锁过程提供了统一的源码设计java模板函数,简化了锁实现的复杂性。核心组件与流程
AQS提供了一套多线程访问共享资源的同步模板,包括tryAcquire、release等核心抽象函数。WriteLock与ReadLock通过继承Sync类,实现了AQS中的tryAcquire、release(写锁)和tryAcquireShared、tryReleaseShared(读锁)函数。 Sync类在ReentrantReadWriteLock中扮演关键角色,它不仅实现了AQS的抽象函数,还通过位运算优化了读写锁状态的存储,减少了资源消耗。此外,Sync类还定义了HoldCounter与ThreadLocalHoldCounter,进一步管理锁的状态与操作。公平与非公平策略
为了适应不同场景的需求,ReentrantReadWriteLock支持公平与非公平策略。通过Sync类的FairSync与NonfairSync子类,实现了读锁与写锁的阻塞控制。公平策略确保了线程按顺序获取锁,而非公平策略允许各线程独立竞争。dbt 源码分析全局图与细节解析
文章最后,构建了一张全局图,清晰展示了ReentrantReadWriteLock的各个组件及其相互关系。通过深入细节,分别解释了读写锁的创建、获取与释放过程。以Lock接口的lock与unlock方法为主线,追踪了从Sync类出发的实现路径,包括tryAcquire、tryRelease等核心函数,以及它们在流程图中的表现。 总结,ReentrantReadWriteLock通过继承AQS并扩展公平与非公平策略,实现了高效、灵活的读写锁功能。通过精心设计的Sync类及其相关组件,确保了多线程环境下的并发控制与资源访问优化。深入理解其内部实现,有助于在实际项目中更好地应用读写锁,提升并发性能与系统稳定性。9.读写锁ReentrantReadWriteLock 的实现原理
了解读写锁之前,想象一下这样的场景:在多个线程中,频繁地进行读取和少量写入操作。如果使用传统的互斥锁,当多个线程同时读取时,虽然没有竞争,但锁仍然会被占用,造成资源浪费。这就是为什么引入读写锁的原因。 ReentrantReadWriteLock 提供了readLock()和writeLock()方法,分别用于获取读锁和写锁,但这些方法获取的并不是实际的锁资源,而是锁对象。另外,getReadLockCount()和getWriteHoldCount()分别统计当前读锁和写锁的持有次数,isWriteLocked()用于判断写锁是否被占用。 通过一个简单的代码演示,我们可以观察到三种可能的结果,这展示了读写锁在实际操作中的灵活性。回到实现原理,ReentrantReadWriteLock基于AQS框架,通过一个state变量管理读写状态。为了解决多种状态表示的问题,它将state变量拆分为多个位,每个位对应一种状态,如读锁和写锁。 具体来说,写锁的获取和释放是这样的:获取写锁的源码:在满足条件后,写锁会被获取,并更新状态。
释放写锁的源码:确保写锁被正确释放,不会导致死锁。
读锁的获取和释放过程类似,但更为复杂,因为它允许线程在持有写锁后获取读锁,然后在读写操作完成后释放锁。这种机制被称为锁降级,以提高并发性能。读写锁ReadWriteLock的实现原理
理解读写锁的实现原理,首先明确几个关键概念。读写锁,顾名思义,可以同时支持读操作和写操作。读操作可以并行,而写操作则具有独占性。读写锁内部使用一个状态变量(如state)来表示锁的当前状态。
读写锁提供了几个核心方法:getReadLockCount()、getReadHoldCount()、getWriteHoldCount()和isWriteLocked()。getReadLockCount()返回读锁的总数量,getReadHoldCount()表示当前线程持有读锁的次数,getWriteHoldCount()则为写锁的持有次数,isWriteLocked()判断当前锁是否处于写锁状态。
实现原理源码分析:核心在于使用一个状态变量state来表示读写锁的状态。state的值可以是以下几种情况:0表示没有锁,1表示写锁,2表示读锁,3表示写锁与读锁同时存在。读锁和写锁之间存在兼容性,即写锁可以重入,读锁也同样可以重入。
写锁的加锁操作,当尝试加锁时,检查state是否为0(无锁状态),如果是,则将state设置为1(写锁状态),并返回成功。如果state已为1或3,则说明已有写锁存在,无法再加写锁,直接返回失败。
读锁的加锁操作,检查state是否为0(无锁状态)或2(已有读锁),如果是,则可成功加锁,将state设置为2(读锁状态),并返回成功。如果state为1(写锁状态)或3(写锁与读锁同时存在),则表示已有写锁存在,读锁无法加锁,返回失败。
写锁与读锁的释放操作,都是将state设置回0,表示锁已经被释放。释放操作后,系统会自动检查是否有其他线程可以加锁。
注意事项:在使用读写锁时,需要特别注意重入锁的情况。读锁和写锁都允许重入,即线程可以多次加锁,但在加锁前应先检查state,避免不必要的操作。
总结:读写锁的实现主要通过状态变量来管理锁的状态,通过方法调用控制锁的加锁和释放。理解状态变量的含义和操作方法是关键。在实际应用中,正确使用读写锁可以显著提高并发程序的性能。
:深入学习Java并发编程,可以参考《Effective Java》、《Java Concurrency in Practice》等书籍,同时关注Java官方文档关于读写锁的说明。