synchronized 和 ReentrantLock

张贤 2020年03月15日 124次浏览

在 Java5 之前,只有synchronized一种锁,在 Java5 之后,增加了ReentrantLockReentrantLock位于 java.util.concurrent.locks 包,和 CountDownLatch、FutureTask、Semaphore 一样基于 AQS 实现,能够实现比synchronized更细粒度的控制,如控制公平性(fairness)。使用ReentrantLock需要注意的是在调用 lock() 方法之后,必须调用 unlock() 释放锁。在 Java6 后经过优化的synchronized性能未必比ReentrantLock低,并且synchronized也是可重入的。

公平锁和非公平锁

  • 公平锁:获取锁的顺序按照调用 lock() 方法的顺序,ReentrantLock可以实现公平锁
  • 非公平锁:抢占的顺序不一定,synchronized时非公平锁

ReentrantLock公平性的设置

//参数为 true 时,倾向于将锁赋予等待时间最久的线程
ReentrantLock lock=new ReentrantLock(true);

在实际场景中,公平性不一定是最重要的,Java 默认的线程调度策略很少会导致饥饿情况的发生,如果要保证公平性,则会引入额外的开销,会导致吞吐量有一定程度的下降,所以只有当实际业务必须实现公平锁的时候,才有必要去使用公平锁。

ReentrantLock可以将锁对象化

  • 可以判断是否由线程,或者某个特定线程在排队等待获取锁
  • 在获取锁时可以设置超时参数,在一定时间内获取不到锁则放弃
  • 可以感知是否成功获取到锁

总结

  • synchronized是关键字,ReentrantLock是类
  • ReentrantLock可以对获取锁的等待时间进行设置,避免死锁
  • ReentrantLock可以获取各种锁的信息
  • ReentrantLock可以灵活地实现多路通知
  • 二者的锁机制是不一样的:synchronized操作的是对象头中的 Mark Word,ReentrantLock是通过调用 Unsafe 类的 park() 方法来获取锁