可重入\不可重入锁?
一、不可重入锁
不可重入锁是指当前线程执行中已经获取了锁,如果再次获取该锁时,就会被阻塞。
下面我们以wait/notify来设计一个不可重入锁(此外还可以通过CAS + 自旋来实现):
//wait、notify实现不可重入锁
public class NonReentrantLockDemo1 {
//记录是否被锁
private volatile boolean locked = false;
public synchronized void lock() {
//当某个线程获取锁成功,其他线程进入等待状态
while (locked) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//加锁成功,locked 设置为 true
locked = true;
}
//释放锁
public synchronized void unlock() {
locked = false;
notify();
}
}
//测试类
class ThreadDemo implements Runnable{
NonReentrantLockDemo lock = new NonReentrantLockDemo();
public static void main(String[] args) {
new Thread(new ThreadDemo()).start();
}
/**
* 方法1:调用方法2
*/
public void method1() {
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + " method1()");
method2();
} finally {
lock.unlock();
}
}
/**
* 方法2:打印前获取 obj 锁
*
*/
public void method2() {
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + " method2()");
} finally {
lock.unlock();
}
}
@Override
public void run() {
method1();
}
}
结果显示:当线程执行到method1时,已经拿到lock锁,只要该锁没有被释放,其他代码块无法使用此锁来加锁。当该线程再去调用method2时,而method2也需要获取lock才能执行,这样都导致了死锁,这种会出现问题的重入一把锁的情况,叫不可重入锁。
二、可重入锁
可重入锁又叫递归锁,指在同一个线程在外层方法获取锁的时候,进入内层方法会自动获取锁。
这里使用一段代码简单演示ReentrantLock可重入:
private static ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) {
System.out.println(lock.getHoldCount());
lock.lock();
System.out.println(lock.getHoldCount());
lock.lock();
System.out.println(lock.getHoldCount());
lock.unlock();
System.out.println(lock.getHoldCount());
lock.unlock();
System.out.println(lock.getHoldCount());
}
0
1
2
1
0
结果显示:同一个线程获取到ReentrantLock锁后,在不释放该锁的情况下可以再次获取。
可重入性优点:
- 避免死锁
- 提升封装性