主题
面试速答(先看这里)
**一句话结论:**如我们常用的synchronized和reentrantLock都是比较典型的可重入锁。
60秒标准回答:
可重入锁是一种多线程同步机制,允许 同一线程 多次获取同一个锁而不会导致死锁。这意味着一个线程可以在持有锁的情况下再次请求并获得相同的锁,而不会被自己阻塞。可重入锁有助于避免死锁和提高代码的可维护性,因为它允许在一个线程中嵌套地调用锁定的方法
如我们常用的synchronized和reentrantLock都是比较典型的可重入锁。也就是说, 在一个线程调用synchronized方法的同时,可以在其方法体内部调用该对象另一个synchronized方法,也就是说一个线程得到一个对象锁后再次请求该对象锁
如以上代码,即可输出
**答题顺序:**结论 → 原理/机制 → 关键流程 → 场景与取舍 → 易错点
回答主线:
- **要点1:**可重入锁是一种多线程同步机制,允许 同一线程 多次获取同一个锁而不会导致死锁。
- **要点2:**在可重入锁的实现上,一般是先要记录下来当前锁是归属于哪个线程的,然后再记录当前锁被重入了多少次。
- **要点3:**在解锁时也同理,锁是当前线程加的,那就重入次数-1,直到等于0的时候,直接解锁。
- **要点4:**以下就是reentrantLock的加锁代码:
- **要点5:**以下就是reentrantLock的解锁代码:
**记忆锚点:**reentrantLock → synchronized → 同一线程 → 候判断是不是当前线程 → 请求并获得相同的锁 → 后再次请求该对象锁
易错提醒:
- 可重入锁有助于避免死锁和提高代码的可维护性,因为它允许在一个线程中嵌套地调用锁定的方法。
- 这样在加锁的时候判断是不是当前线程持有的锁,如果是则重入次数+1,否则重入失败。
追问准备:
- 围绕「reentrantLock」:底层原理是什么?使用时有哪些边界和常见坑?
- 围绕「synchronized」:底层原理是什么?使用时有哪些边界和常见坑?
- 围绕「同一线程」:底层原理是什么?使用时有哪些边界和常见坑?
- 如果线上出现异常,你会如何定位、验证并规避?
典型回答
可重入锁是一种多线程同步机制,允许同一线程多次获取同一个锁而不会导致死锁。这意味着一个线程可以在持有锁的情况下再次请求并获得相同的锁,而不会被自己阻塞。可重入锁有助于避免死锁和提高代码的可维护性,因为它允许在一个线程中嵌套地调用锁定的方法。
如我们常用的synchronized和reentrantLock都是比较典型的可重入锁。也就是说,在一个线程调用synchronized方法的同时,可以在其方法体内部调用该对象另一个synchronized方法,也就是说一个线程得到一个对象锁后再次请求该对象锁。
plain
public class ReentrantLockTest {
public static void main(String[] args) {
ReentrantLockTest reentrantLockTest = new ReentrantLockTest();
reentrantLockTest.method1();
}
public synchronized void method1(){
method2();
System.out.println("invoke method1");
}
public synchronized void method2() {
System.out.println("invoke method2");
}
}如以上代码,即可输出:
plain
invoke method2
invoke method1在可重入锁的实现上,一般是先要记录下来当前锁是归属于哪个线程的,然后再记录当前锁被重入了多少次。这样在加锁的时候判断是不是当前线程持有的锁,如果是则重入次数+1,否则重入失败。
在解锁时也同理,锁是当前线程加的,那就重入次数-1,直到等于0的时候,直接解锁。
以下就是reentrantLock的加锁代码:
plain
if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}以下就是reentrantLock的解锁代码:
plain
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}