ReentrantLock实现原理?

ReentrantLock 是可重入的独占锁,只能有一个线程可以获取该锁,其它获取该锁的线程会被阻塞而被放入该锁的阻塞队列里面。

看看ReentrantLock的加锁操作:

// 创建非公平锁
ReentrantLock lock = new ReentrantLock();
// 获取锁操作
lock.lock();
try {
    // 执行代码逻辑
} catch (Exception ex) {
    // ...
} finally {
    // 解锁操作
    lock.unlock();
}

new ReentrantLock() 构造函数默认创建的是非公平锁 NonfairSync。

公平锁 FairSync

  1. 公平锁是指多个线程按照申请锁的顺序来获取锁,线程直接进入队列中排队,只有队列中的第一个线程才能获得锁。
  2. 公平锁的优点是等待锁的线程不会被饿死(Starvation)。然而,整体吞吐效率相对于非公平锁要低,因为等待队列中除第一个线程以外的所有线程都会被阻塞,唤醒阻塞线程的开销比非公平锁大。

非公平锁 NonfairSync

  • 非公平锁是多个线程在加锁时直接尝试获取锁,如果获取不到,它们才会到等待队列的队尾等待。但是,如果此时锁刚好可用,那么线程可以无需阻塞直接获取到锁。
  • 非公平锁的优点是可以减少唤醒线程的开销,整体的吞吐效率更高,因为线程有机会在不阻塞的情况下直接获得锁,CPU无需唤醒所有线程。然而,等待队列中的线程可能会被饿死(Starvation),或者需要等待很长时间才能获得锁。

在默认情况下创建的锁对象(lock())时:

  • 如果锁当前没有被其他线程占用,并且当前线程之前没有获取过该锁,则当前线程会获取到该锁,将当前线程设置为锁的拥有者,并将AQS的状态值设置为1,然后直接返回。如果当前线程之前已经获取过该锁,则只是简单地将AQS的状态值加1后返回。
  • 如果锁已经被其他线程持有,非公平锁会尝试获取锁。如果获取失败,当前线程会被放入AQS队列中阻塞挂起。

标签: java, Java面试题, Java问题合集, Java编程, Java问题精选, Java常见问题