转载请注明出处https://blog.csdn.net/Fury97/article/details/81367900
目录
重入锁
顾名思义,就是可以支持重进入的锁,它表示该锁能够支持一个线程对资源的重复加锁。
为什么需要重入锁
使用重入锁,可以在当一个线程获取对象A的锁之后,这个线程可以再次获取对象A上的锁。
假设某一同步方法是递归方法,那么就会不停的对此对象加锁,如果不使用重入锁,会导致线程1本身获取了对象A的锁,再获取锁时被阻塞住。
重入锁有哪些
我们常见的synchronized就是重入锁,而第二个重入锁ReentrankLock就是我们今天的主题。
ReentrankLock如何实现重入
首先明确概念:重入是指任意线程在获取到锁之后能够再次获取该锁而不会被阻塞。
实现该特性需要解决两个问题:
- 锁需要去识别获取锁的线程是否为当前占据锁的线程,如果是,则成功获取。
- 线程重复n次获取了锁,那么就要释放n次锁,否则其他线程还是无法获取该锁。ReentrankLock通过要求每次获取锁时进行计数自增,当锁被释放时,计数自减,计数为0时表示锁成功释放。所以前(n-1)次tryRelease()方法都是返回false,只有最后一次才返回true。
公平锁与不公平锁
公平锁:对于每一个线程来说,获取锁的顺序取决于线程提交请求的先后顺序。也就是FIFO,排队领锁,先来先得。
不公平锁:随缘。
我们常见的synchronized是不公平锁,所以使用synchronized有可能会出现某线程永远得不到锁而一直被阻塞。
而ReentrankLock给我们提供了一个构造函数,我们可以通过构造函数来控制锁是否是公平的。
ReentrankLock中公平锁的实现方法
在同步队列中添加对“当前节点是否有前驱节点的判断”。
同步队列是一个队列,每一个获取锁失败的线程会成为队列中的一个节点,当持有锁的线程释放锁时会发出信号,让后面的节点的线程申请锁。
所以当前节点如果有前驱节点,即说明有比它来的更早的线程在前面,因此需要等待前驱节点中的线程获取并释放锁后,才能继续申请锁。
公平锁和非公平锁的优缺点
- 公平锁没有非公平锁效率高,因为在非公平锁中经常会出现刚释放锁的线程再次获取了锁,而公平锁中线程需要不停切换。
- 公平锁可以减少“饥饿”发生的概率,因为它总是保证来的最早的线程获得锁,而非公平锁不能保证。
参考资料:《Java并发编程的艺术》