ReentrantLock

54 阅读1分钟

ReentrantLockjava.util.concurrent.locks 包里的可重入互斥锁,功能比 synchronized 更灵活。提供了超时、中断、轮询、公平锁与非公平锁等功能。

synchronized相同,它也是可重入的,内部维护计数器。

核心 API

  • 基础上锁/解锁
Lock lock = new ReentrantLock();
lock.lock();
try { /* TODO */ }
finally { lock.unlock(); }
  • 非阻塞尝试上锁
if (lock.tryLock()) {
    try { /* TODO */ }
    finally { lock.unlock(); }
} else {
    // 获取失败的退让策略
}
  • 限时尝试上锁
if (lock.tryLock(500, TimeUnit.MILLISECONDS)) {
    try { /* TODO */ }
    finally { lock.unlock(); }
}

公平锁与非公平锁

  • 构造: new ReentrantLock(true) 为公平锁,false(默认)为非公平。

  • 公平锁: 锁被释放后,先来先得,性能较差,为了保证顺序上下文切换更频繁。

  • 非公平锁: 锁被释放后,后来的线程可能先获取锁,性能更好,可能导致个别线程长期等待。

与 AQS 的关系

ReentrantLock 是基于AQS「AbstractQueuedSynchronizer」实现,AQS提供队列、阻塞/唤醒与内存语义,ReentrantLock 只需覆写获取/释放的策略。

ReentrantLock 的同步器为 SyncSync 是 AQS 的子类,添加锁和释放锁的大部分操作都在Sync 当中实现。Sync 有两个子类,FairSync 为公平锁 NonfairSync 为非公平锁。

与 synchronized 对比

  • synchronized
    • 依赖于 JVM
    • 有锁升级机制,在低竞争状态下会比较快
    • 语法简洁、异常安全、无忘记 unlock()风险
  • ReentrantLock
    • JDK 层面的实现
    • 可以通过 lockInterruptibly 中断获取
    • 可以通过 tryLock 限时/非阻塞获取
    • 可实现公平锁