1.ReentrantLock的简单介绍:
ReentrantLock是Java并发包中提供的一个可重入的互斥锁。ReentrantLock和Synchronized在基本用法,行为语义上都是类似的。同样都具有可重入性。但是ReentrantLock可以实现公平锁。
2.ReentrantLock具有可重入性,公平锁,非公平锁。
可重入性:所谓可重入性,就是可以支持一个线程重复获取锁。
公平锁:是指获取锁的策略相对公平,当多个线程获取同一把锁时,必须按照申请锁的时间排好序依次获取锁,不能插队。
非公平锁:当锁释放时,所有等待线程都有机会获取锁。
synchronized是非公平锁,ReentrantLock默认也是可以非公平锁,但是可以通过带boolean参数的构造函数来指定使用公平锁。
而且非公平锁性能一般比公平锁要高。
3.内部分析:
ReentrantLock是基于AQS的,AQS是Java并发包中众多同步组件的构建基础,他通过一个int类型的状态变量state和一个FIFO的队列来获取共享资源,线程排队等等。AQS是一个底层框架,采用模板方法模式,它定义了通用的较复杂的逻辑骨架,比如线程的排队,阻塞,唤醒等。将这些复杂但实质通用的部分抽取出来,这些都是需要构建同步组件的使用者无需关心的,使用者只需重写一些简单的指定的方法就可以了。
1.ReentrantLock的处理逻辑:
其内部定义了三个重要的静态内部类:Sync,NonFairSync,FairSync。Sync作为ReentrantLock中公用的同步组件,继承了AQS,NonFairSync和FairSync继承了Sync,调用Sync的公用逻辑,然后再在各自内部完成自己的特定逻辑。(公平或非公平)
2.两者的lock()方法实现原理:
NonFairSync(不公平锁)
1.先获取state的值,如果值为0,说明此时没有线程获取到资源,那么CAS操作将值设为1,设置成功就代表获取到排他锁了。
2.如果state值大于0,则说明已经有线程抢占资源了。此时再去判断是否是自己抢占的,如果是,state累加,返回true,重入成功,state的值就是线程重入次数。
3.其他情况,获取锁失败。
FairSync(公平锁)
公平锁和非公平锁的逻辑大致是一样,不同的是有了!hasQueuedPredecessors()(判断是否有线程排在自己之前)这个判断逻辑,即便state=0,也不能贸然直接去获取,要看看是否还有线程在排队。若没有,才可以尝试去获取,做后面的处理,反之,返回false,获取失败。
3.ReentrantLock的tryRelease()方法实现原理:
若state=0,说明此时线程已经释放完了,返回true,上层AQS会意识到资源空出来了。若不为0,则说明,线程还在占有资源,只是释放了这一次重入的资源而已。返回false。
总结:
ReentrantLock是一种可重入的,可实现公平性的互斥锁。它的设计基于AQS框架,可重入和公平性的实现逻辑都不难理解,每重入一次,state就加1,当然释放也要一层一层释放。至于公平性,就是尝试去获取锁的时候,去看看同步队列里面是否有比自己申请早的线程在等待,如果有,就继续等待,如果没有,才去抢占锁。