什么是可重入锁
可重入锁又名递归锁,是指同一个线程在外层方法获取锁的时候,再进入该线程的内层方法会自动获取锁,前提是锁对象得是同一个对象,不会因为之前已经获取过锁还没释放而阻塞。
Java中 显示锁ReentrantLock 和 隐式锁Synchronized 都是可重入锁,它的好处是可一定程度避免死锁。
/**
* @Description: 同步代码块演示可重入锁
* @date Date : 2021年06月06日 10:58
*/
public class ReEnterLockTest {
static Object lock = new Object();
public static void main(String[] args) {
Thread t = new Thread(() -> {
synchronized (lock){
System.out.println(Thread.currentThread().getName() + "\t" + "------外层调用");
synchronized (lock){
System.out.println(Thread.currentThread().getName() + "\t" + "------中层调用");
synchronized (lock){
System.out.println(Thread.currentThread().getName() + "\t" + "------内层调用");
}
}
}
},"t");
t.start();
}
}
可重入锁 Synchronized 的实现原理
每个锁对象拥有一个锁计数器和一个指向持有该锁的线程的指针,当执行 monitorenter 时,如果目标锁对象的计数器为零,说明没有被其他线程持有,jvm 会将该锁对象的持有线程设置为当前线程,并且将计数器加1。在目标锁对象的计数器不为零的情况下,如果锁对象的持有线程是当前线程,那么jvm会将其计数器加1,否则就会将此线程阻塞,直到持有线程释放该锁。当执行monitorexit,jvm则需要将锁对象的计数器减1,计数器为0代表锁已释放。
sleep() 与 wait() 的区别
- sleep 是 Thread 的方法,而 wait 是 Object 的方法
- sleep 不需要强制和 synchronized 配合使用,但 wait 需要和 synchronized 一起用
- sleep 在睡眠的同时,不会释放对象锁,但 wait 在等待的时候会释放对象锁