MST

星途 面试题库

面试题:Java并发包中ReentrantLock与synchronized的比较及选择

Java并发包中的ReentrantLock和synchronized关键字都能实现线程同步控制。请深入比较两者在功能特性、性能表现、使用场景等方面的差异。在一个高并发读写的场景下,何时应优先选择ReentrantLock,何时synchronized更合适,说明理由。
13.3万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

功能特性差异

  1. 锁的获取方式
    • synchronized:是隐式锁,由JVM自动获取和释放。当线程进入同步代码块或方法时自动获取锁,退出时自动释放。
    • ReentrantLock:是显式锁,需要手动调用lock()方法获取锁,调用unlock()方法释放锁,且必须在finally块中释放锁以确保锁一定会被释放,避免死锁。
  2. 可中断性
    • synchronized:不可中断,一旦线程获取到锁进入同步块,除非正常执行完毕或者抛出异常,否则其他线程无法中断它。
    • ReentrantLock:可以通过lockInterruptibly()方法在等待锁的过程中响应中断。
  3. 公平性
    • synchronized:是非公平锁,线程获取锁的顺序是随机的,在高并发情况下可能导致某些线程长时间等待(线程饥饿)。
    • ReentrantLock:默认是非公平锁,但可以通过构造函数创建公平锁,公平锁会按照请求锁的顺序来分配锁,减少线程饥饿现象,但公平锁的性能一般低于非公平锁。
  4. 锁的绑定多个条件
    • synchronized:一个锁只能与一个Objectwait - notify机制关联。
    • ReentrantLock:可以通过newCondition()方法创建多个Condition对象,每个Condition对象都可以实现类似wait - notify的功能,适用于更复杂的线程间通信场景。

性能表现差异

  1. JDK早期版本 在低并发情况下,synchronized和ReentrantLock性能相近。但在高并发情况下,synchronized由于采用重量级锁,性能较差,而ReentrantLock使用乐观锁机制和CAS操作,性能更优。
  2. JDK 1.6及以后 synchronized进行了大量优化,引入偏向锁、轻量级锁等机制,性能有了很大提升。在竞争不激烈的情况下,synchronized性能甚至优于ReentrantLock;在竞争激烈时,ReentrantLock性能仍可能更好,特别是需要可中断锁、公平锁等特性时。

使用场景差异

  1. 高并发读写场景
    • 优先选择ReentrantLock的情况
      • 当读操作和写操作的线程都需要可中断性时,例如在某些情况下需要取消正在等待锁的线程操作,ReentrantLock可以通过lockInterruptibly()方法满足需求,而synchronized无法实现。
      • 当需要公平锁来保证所有线程都有机会获取锁,减少线程饥饿现象时,ReentrantLock可以通过构造函数创建公平锁,而synchronized是非公平锁。
      • 当需要更灵活的线程间通信,例如使用多个Condition来实现不同条件下的等待和唤醒时,ReentrantLock更合适。
    • 优先选择synchronized的情况
      • 当读写操作竞争不激烈,代码追求简洁性时,synchronized作为隐式锁,代码书写更简洁,无需手动管理锁的获取和释放,JVM的优化也能保证较好的性能。
      • 当需要与其他使用synchronized的代码进行兼容,避免混合使用不同的锁机制导致复杂的问题时,应选择synchronized。