MST

星途 面试题库

面试题:Java中如何通过锁机制保证线程安全?

请阐述在Java中,synchronized关键字和ReentrantLock在实现线程安全方面的原理、使用场景及它们之间的主要区别。
12.1万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

原理

  1. synchronized关键字
    • 对象头:Java对象头中有一部分用于存储对象的锁信息。当一个线程访问被synchronized修饰的代码块或方法时,它会尝试获取对象的锁。如果锁可用,线程会将对象头中的锁标志位设置为相应的状态(偏向锁、轻量级锁或重量级锁,具体取决于竞争情况)。
    • Monitor机制:在底层,synchronized依赖于JVM的Monitor机制。Monitor可以理解为一个同步工具,也可以说是一种同步机制,它包含一个计数器和一个等待队列。当线程获取到Monitor时,计数器加1,当线程释放Monitor时,计数器减1。如果计数器为0,其他线程就可以竞争获取Monitor。
  2. ReentrantLock
    • AQS框架ReentrantLock基于AbstractQueuedSynchronizer(AQS)框架实现。AQS使用一个FIFO队列来管理等待获取锁的线程。当一个线程尝试获取锁时,如果锁不可用,线程会被封装成一个Node节点加入到队列中。当持有锁的线程释放锁时,会从队列中唤醒一个等待线程。
    • 可重入性实现ReentrantLock内部维护了一个持有锁的线程标识和一个重入次数计数器。当同一个线程再次获取锁时,重入次数加1,释放锁时重入次数减1,当重入次数为0时,锁被真正释放。

使用场景

  1. synchronized关键字
    • 简单场景:适用于简单的同步需求,代码量较少,例如对一个方法或代码块进行同步,无需复杂的锁控制。
    • 内置锁场景:当需要使用对象内置的锁机制,并且不需要额外的高级功能(如公平锁、可中断锁等)时,synchronized是一个很好的选择。
  2. ReentrantLock
    • 复杂场景:适用于需要更灵活、更高级的锁控制的场景。例如,需要实现公平锁(按照线程等待的顺序获取锁),ReentrantLock可以通过构造函数设置为公平锁。
    • 可中断场景:当需要支持线程在等待锁的过程中可以被中断时,ReentrantLocklockInterruptibly()方法可以满足需求,而synchronized关键字不支持可中断的锁获取。
    • 多条件场景ReentrantLock可以创建多个Condition对象,实现更细粒度的线程间通信和同步,而synchronized只能通过Objectwait()notify()notifyAll()方法进行简单的线程间通信。

主要区别

  1. 锁的获取方式
    • synchronized关键字:是隐式获取锁,当进入synchronized修饰的代码块或方法时,自动获取锁,退出时自动释放锁,无需手动操作。
    • ReentrantLock:是显式获取锁,需要调用lock()方法获取锁,使用完后必须调用unlock()方法释放锁,否则可能导致死锁。
  2. 锁的公平性
    • synchronized关键字:是非公平锁,线程在竞争锁时,不考虑等待队列中线程的顺序,新到来的线程有可能直接获取到锁,即使等待队列中有其他线程等待时间更长。
    • ReentrantLock:默认是非公平锁,但可以通过构造函数设置为公平锁,公平锁会按照线程在等待队列中的顺序分配锁,减少线程饥饿现象。
  3. 锁的可中断性
    • synchronized关键字:获取锁的过程是不可中断的,一旦线程进入等待获取锁的状态,除非获取到锁或者发生异常,否则不会被中断。
    • ReentrantLock:提供了lockInterruptibly()方法,允许线程在等待锁的过程中被中断,通过这种方式可以更好地控制线程的执行流程。
  4. 锁的绑定条件
    • synchronized关键字:与对象的内置锁绑定,一个对象只有一把锁,只能通过Objectwait()notify()notifyAll()方法进行线程间通信。
    • ReentrantLock:可以绑定多个Condition对象,每个Condition对象可以实现不同的等待和唤醒策略,实现更灵活的线程间同步和通信。
  5. 性能方面
    • 在JDK早期版本中,synchronized的性能相对较差,因为它是重量级锁,涉及到操作系统内核态和用户态的切换。随着JDK的发展,synchronized进行了很多优化,如偏向锁、轻量级锁等,性能有了很大提升。
    • ReentrantLock:在高竞争环境下,ReentrantLock的性能可能优于synchronized,因为它可以通过设置公平锁、使用非公平锁的优化策略等方式来提高性能。但在低竞争环境下,synchronized的性能可能更好,因为它的使用更简单,开销更小。