ReentrantLock的使用
使用ReentrantLock进行同步
ReentrantLock lock = new ReentrantLock(false);//false为非公平锁,true为公平锁
lock.lock() //加锁
// 处理逻辑
lock.unlock() //解锁
ReentrantLock是一种基于AQS框架的应用实现,是JDK中的一种线程并发访问的同步手段,它的功能类似于synchronized是一种互斥锁,可以保证线程安全。而且它具有比synchronized更多的特性,比如它支持手动加锁与解锁,支持加锁的公平性。
ReentrantLock如何实现synchronized不具备的公平与非公平性呢?
- 在ReentrantLock内部定义了一个Sync的内部类,该类继承AbstractQueuedSynchronized,对该抽象类的部分方法做了实现;并且还定义了两个子类
- FairSync 公平锁的实现
- NonfairSync 非公平锁的实现
- 这两个类都继承自Sync,也就是间接继承了AbstractQueuedSynchronized
- 所以这一个ReentrantLock同时具备公平与非公平特性。上面主要涉及的设计模式:模板模式-子类根据需要做具体业务实现。
ReentrantLock实现重进入
重进入是指任意线程在获取到锁之后能够再次获取该锁而不会被锁所阻塞,该特性的实现需要解决一下两个问题:
1、线程再次进入
:锁需要去识别获取锁的线程是否为当前占据锁的线程,如果是,则再次成功获取。
2、锁的最终释放
:线程重复n次获取了锁,随后在第n次释放该锁后,其他线程能够获取到该锁。锁的最终释放要求锁对于获取进行技术自增,技术表示当前锁被重复获取的次数,而锁被释放时,计数自减去,当技术为0时表示锁已经成功释放。
成功获取锁的线程再次获取锁,只是增加了同步状态值。
如果该锁被获取了n
次,那么前(n-1)
次tryRelease(int releases)
方法必须返回false,而只有同步状态完全释放了,才能返回true。可以看到,该方法将同步状态是否为0作为最终释放的条件,当同步状态为0时,将占有线程设置为null,并返回true,表示释放成功。
详细请参考:
https://blog.youkuaiyun.com/yanyan19880509/article/details/52345422
公平锁
锁的获取顺序应该符合请求的绝对时间顺序,也就是 FIFO
。
ReentrantLock的构造函数中,默认的无参构造函数将会把Sync对象创建为NonfairSync对象,这是一个“非公平锁”;而另一个构造函数ReentrantLock(boolean fair)传入参数为true时将会把Sync对象创建为“公平锁”FairSync。
非公平锁
只要CAS设置同步状态成功,则表示当前线程获取了锁。
nonfairTryAcquire(int acquires)
方法,对于非公平锁,只要CAS设置同步状态成功,则表示当前线程获取了锁,而公平锁则不同。tryAcquire方法,该方法与nonfairTryAcquire(int acquires)比较,唯一不同的位置为判断条件多了hasQueuedPredecessors()方法,即加入了同步队列中当前节点是否有前驱节点的判断,如果该方法返回true,则表示有线程比当前线程更早地请求获取锁,因此需要等待前驱线程获取并释放锁之后才能继续获取锁。