概念
可重入锁,指的是同一线程外层函数(方法)获得锁之后,内层函数(方法)仍然能获得该锁的代码,同一线程在外层方法获取锁的时候,再进入内层方法会自动获取锁。
简言之:已经获得该锁的线程,可以重复再次进入被该锁锁定的代码块。
ReentrantLock 能够代替 synchronized 关键字完成独占锁的功能,并且允许占有锁线程的重入,显示地调用lock()、unlock()方法使得代码更灵活,收缩性更好。
注意:我们常用的 synchronized 也是典型的可重入锁!
可重入锁是独占锁!独占-----即同一时间只能有一个线程持有锁。
还不理解……直接上 Demo
可重入锁Demo
1.基于 ReentrantLock 实现
/**
* TODO 可重入锁Demo
*
* @author liuzebiao
* @Date 2019-12-25 15:11
*/
public class ReentrantLockDemo {
Lock lock = new ReentrantLock();//默认为非公平锁,构造器无参/传false, 公平锁需要传 true
/**
* 吃饭
*/
public void eat(){
lock.lock();
try {
System.out.println(Thread.currentThread().getName()+":开始吃饭");
//进入另一个加锁方法
sleep();
} finally {
lock.unlock();
}
}
/**
* 睡觉
*/
public void sleep(){
lock.lock();
try {
System.out.println(Thread.currentThread().getName()+":开始睡觉");
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
ReentrantLockDemo demo = new ReentrantLockDemo();
new Thread(()->{
demo.eat();
},"Mary").start();
new Thread(()->{
demo.eat();
},"Lucy").start();
}
}
测试结果:
Mary:开始吃饭
Mary:开始睡觉
Lucy:开始吃饭
Lucy:开始睡觉
2.基于 synchronized 实现
/**
* TODO 基于synchronized,可重入锁Demo
*
* @author liuzebiao
* @Date 2019-12-25 15:11
*/
public class SynchronizedDemo {
/**
* 吃饭
*/
public synchronized void eat(){
System.out.println(Thread.currentThread().getName()+":开始吃饭");
//进入另一个加锁方法
sleep();
}
/**
* 睡觉
*/
public synchronized void sleep(){
System.out.println(Thread.currentThread().getName()+":开始睡觉");
}
public static void main(String[] args) {
SynchronizedDemo demo = new SynchronizedDemo();
new Thread(()->{
demo.eat();
},"Mary").start();
new Thread(()->{
demo.eat();
},"Lucy").start();
}
}
测试结果:
Mary:开始吃饭
Mary:开始睡觉
Lucy:开始吃饭
Lucy:开始睡觉
^_^ 到这儿应该就理解了 可重入锁的概念了吧
可重入锁实现原理
每一个锁关联一个owner 线程持有者 和 state 计数器,当计数器为 0 时表示该锁没有被任何线程持有,那么任何线程都可能获得该锁而调用相应的方法;当某一线程请求成功后,JVM 会记下锁的持有线程,并且将计数器置为 1;此时其它线程请求该锁,则必须等待;而该持有锁的线程如果再次请求这个锁,就可以再次拿到这个锁,同时计数器会递增;当线程退出同步代码块时,计数器会递减,如果计数器为 0,则释放该锁。(源码层面分析)
附:原理分析
本文仅介绍如何使用,如需了解 ReentrantLock 原理(源码分析),请跳转了解:可重入锁 ReentrantLock 原理分析
可重入锁 ReentrantLock 的用法,介绍到此为止
如果本文对你有所帮助,那就给我点个赞呗 ^_^
End