【并发专题】ReentrantLock连环炮
本问题对应的项目链接:高频题回答模版训练
1、简单介绍下 ReentrantLock?
2、synchronized和ReentrantLock有什么区别?
3、既然说到了可重入锁,那你觉得为啥需要可重入锁?
4、ReentrantLock 底层是怎么实现的?
本问题对应的项目链接:高频题回答模版训练
1、简单介绍下 ReentrantLock?
2、synchronized和ReentrantLock有什么区别?
3、既然说到了可重入锁,那你觉得为啥需要可重入锁?
4、ReentrantLock 底层是怎么实现的?
共以下 4 个回答
1、简单介绍下 ReentrantLock?
ReentrantLock是AQS实现的一个子类,是一种可重入锁,同一个线程可以数次获取该锁,内部有一个计数器,获取锁计数器+1,释放锁计数器-1,只有计数器为0时其他线程才能获取该锁。
2、synchronized和ReentrantLock有什么区别?
synchronized是隐形可重入的,在递归执行同步块的时候不被阻塞,而ReentrantLock需要显式调用lock方法去加锁。ReentrantLock更加灵活,支持trylock方法,可以尝试获取锁而不阻塞,同时可以设置锁的公平性。
3、既然说到了可重入锁,那你觉得为啥需要可重入锁?
主要是解决线程请求同一个锁时出现的死锁问题,比如在递归的逻辑中涉及获取锁的操作
4、ReentrantLock 底层是怎么实现的?
AQS的state的值代表锁获取的状态,每次同一个线程获取锁的时候state就+1,释放锁则-1,只有state为0的时候才代表锁被完全释放。
1、简单介绍下 ReentrantLock?
ReentrantLock是一种可重入锁,线程获取到当前对象锁之后,还可以继续获取对象的锁,ReentranLock包含了Sync内部类来实现,Sync实现了公平锁和非公平锁,相比于Synchronized关键字做了大量的优化,比如实现了等待、通知、中断等操作。
2、synchronized和ReentrantLock有什么区别?
– 都是可重人锁
– synchronized是重量级锁,锁升级的过程是不可逆的,而且依赖于JVM底层的指令实现获得锁和解锁的操作;ReentrantLock基于JDK实现的,通过Lock()和Unlock()来实现获得锁和释放锁;
– 中断机制:调用LockInterrupted()方法可以中断锁的执行,线程转而处理其它等待的任务;
– 非公平锁:ReentrantLock使用构造函数可以指定是属于公平锁还是非公平锁,默认是使用非公平锁;而synchronized关键字只支持非公平锁;
– 通知:synchronized结合notify()和notifyall()从锁池中唤醒正在等待的线程,进入等待池获取资源;而ReentrantLock一般结合Condition来唤醒线程获取资源。
3、既然说到了可重入锁,那你觉得为啥需要可重入锁?
可重入锁就是获取了当前对象的锁,继续访问线程资源还可以再次获取到当前对象的锁,加如不是可重入锁,当线程想要获取锁对象的资源就会造成等待阻塞的情况,也就是禅山了死锁的现象;
使用场景:在使用递归函数获取锁,就会不断循环获取当前对象的锁,在每次递归时就会被自己阻塞,通过可重如锁就可以避免死锁现象的发省。
****4、ReentrantLock 底层是怎么实现的?
ReentrantLock 需要在 AQS 的基础上多考虑两个问题,一个是获取锁的线程再次获取锁的判断,此时需要将底层表示同步状态 volatile int 类型的值 + 1。另一个是锁的最终释放,线程重复获取 n 次锁,那么释放时也要重复释放 n 次,对应同步状态的值自减,直至为 0 代表锁已成功释放。
1、ReentrantLock是Lock接口的一个实现类,底层基于CAS和AQS实现,利用一个volatile变量state来表示锁的状态,ReentrantLock中文意思是可重入锁,允许同一个线程多次获取同一把锁,而不至于造成死锁。它支持公平锁和非公平锁,支持响应中断。公平锁保证先进来的线程优先获取锁,而非公平锁允许插队,可能造成有些线程一直获取不到锁,但是它性能好。
2、synchronized是java的一个关键字,可以用来修饰方法或者代码块,优化过之后引入了锁粗化、偏向锁和自旋锁,synchronized不支持超时等待,一进入就要等他执行完成之后自己释放锁,如果获取不到锁会一直阻塞直到获取到或者抛出异常,它是隐式获取锁和释放锁,在进入和退出同步代码块的时候自动执行,不需要手动处理异常情况;
ReentrantLock使用更加灵活,支持响应中断,可以设置超时时间,如果一个线程在等待锁的时间过长,可以让他自动放弃,或者根据返回结果作出不同的动作,而不是一直等待;它需要显式地获取锁和释放锁,并且要在finally当中释放锁,防止出现异常导致锁无法释放。
实际上synchronized和ReentrantLock都是可重入锁。
3、可重入锁的意思是,同一个线程,第一次获取了锁,在没有释放的情况下,可以继续获取这个锁,而不会被阻塞。如果锁不是可重入的,那么同一个线程,对自己所拥有的锁不能重复获取,如果这个线程要获取锁,那它要等自己释放这个锁,这个时候会造成死锁;比如,在一个同步方法调用另一个同步方法,如果不用可重入锁,那么第二次请求锁的时候就会发生异常
4、ReentrantLock 底层基于CAS和AQS实现。具体来说,一个线程调用lock方法,首先获取state变量,看看锁的状态,有没有被其它线程获取,如果没有那把这个线程设置为独占线程,如果有,根据公平锁和非公平锁的设置,有不同的处理方法。
对于公平锁,会进入等待队列,这个队列里面等待的线程,先进去的会先被唤醒,保证公平的原则;
对于非公平锁,会尝试再获取一次这个锁,如果还是不行,就进入等待队列,队列里面所有等待的线程,获取到锁的机会是一样的,等这个锁被释放的时候,如果这个时候有新的线程来竞争这个锁,那么这个新的线程可以优先获取这个锁,因为这样可以减少CAS的操作次数,降低锁的竞争强度,提高性能
1、简单介绍下 ReentrantLock?
ReentrantLock 是 Java 中重入锁的一种实现,可以支持一个线程对某个资源的重复加锁,底层是基于 AQS 实现,在同一个线程加锁时递增,释放锁时递减同步状态的值。
2、synchronized 和 ReentrantLock 有什么区别?
两者相同之处在于都支持重入性,synchronized 支持隐性的重进入,比如线程可以在递归执行同步块里的代码而不被阻塞,ReentrantLock 需要显示调用 lock( )。
不同之处在于 ReentrantLock 比 synchronized 更加灵活。ReentrantLock 提供有 tryLock( ),可以尝试获取锁而不阻塞,并且可以设置超时时间。除此之外 ReentrantLock 还支持获取锁时的公平和非公平性选择。
3、既然说到了可重入锁,那你觉得为啥需要可重入锁?
可重入锁主要是用来解决线程在持有锁的情况下,再次请求同一个锁时发生的死锁问题。如果没有可重入锁,当一个线程已经获取了锁后,再次请求该锁会导致自己要等待自己释放锁,进而产生死锁。
具体的场景比如,递归函数中需要获取锁,如果没有重入锁,线程在每次递归调用时都会被自己阻塞。还有多个方法可能都需要获取相同的锁,没有重入锁的话,它们之间就不能相互调用。
4、ReentrantLock 底层是怎么实现的?
ReentrantLock 需要在 AQS 的基础上多考虑两个问题,一个是获取锁的线程再次获取锁的判断,此时需要将底层表示同步状态 volatile int 类型的值 + 1。另一个是锁的最终释放,线程重复获取 n 次锁,那么释放时也要重复释放 n 次,对应同步状态的值自减,直至为 0 代表锁已成功释放。
5、demo