Skip to content

面试速答(先看这里)

**一句话结论:**如我们常用的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;
}