面试题答案
一键面试原理
- synchronized关键字:
- 对象头:Java对象头中有一部分用于存储对象的锁信息。当一个线程访问被
synchronized
修饰的代码块或方法时,它会尝试获取对象的锁。如果锁可用,线程会将对象头中的锁标志位设置为相应的状态(偏向锁、轻量级锁或重量级锁,具体取决于竞争情况)。 - Monitor机制:在底层,
synchronized
依赖于JVM的Monitor机制。Monitor可以理解为一个同步工具,也可以说是一种同步机制,它包含一个计数器和一个等待队列。当线程获取到Monitor时,计数器加1,当线程释放Monitor时,计数器减1。如果计数器为0,其他线程就可以竞争获取Monitor。
- 对象头:Java对象头中有一部分用于存储对象的锁信息。当一个线程访问被
- ReentrantLock:
- AQS框架:
ReentrantLock
基于AbstractQueuedSynchronizer(AQS)框架实现。AQS使用一个FIFO队列来管理等待获取锁的线程。当一个线程尝试获取锁时,如果锁不可用,线程会被封装成一个Node节点加入到队列中。当持有锁的线程释放锁时,会从队列中唤醒一个等待线程。 - 可重入性实现:
ReentrantLock
内部维护了一个持有锁的线程标识和一个重入次数计数器。当同一个线程再次获取锁时,重入次数加1,释放锁时重入次数减1,当重入次数为0时,锁被真正释放。
- AQS框架:
使用场景
- synchronized关键字:
- 简单场景:适用于简单的同步需求,代码量较少,例如对一个方法或代码块进行同步,无需复杂的锁控制。
- 内置锁场景:当需要使用对象内置的锁机制,并且不需要额外的高级功能(如公平锁、可中断锁等)时,
synchronized
是一个很好的选择。
- ReentrantLock:
- 复杂场景:适用于需要更灵活、更高级的锁控制的场景。例如,需要实现公平锁(按照线程等待的顺序获取锁),
ReentrantLock
可以通过构造函数设置为公平锁。 - 可中断场景:当需要支持线程在等待锁的过程中可以被中断时,
ReentrantLock
的lockInterruptibly()
方法可以满足需求,而synchronized
关键字不支持可中断的锁获取。 - 多条件场景:
ReentrantLock
可以创建多个Condition
对象,实现更细粒度的线程间通信和同步,而synchronized
只能通过Object
的wait()
、notify()
和notifyAll()
方法进行简单的线程间通信。
- 复杂场景:适用于需要更灵活、更高级的锁控制的场景。例如,需要实现公平锁(按照线程等待的顺序获取锁),
主要区别
- 锁的获取方式:
- synchronized关键字:是隐式获取锁,当进入
synchronized
修饰的代码块或方法时,自动获取锁,退出时自动释放锁,无需手动操作。 - ReentrantLock:是显式获取锁,需要调用
lock()
方法获取锁,使用完后必须调用unlock()
方法释放锁,否则可能导致死锁。
- synchronized关键字:是隐式获取锁,当进入
- 锁的公平性:
- synchronized关键字:是非公平锁,线程在竞争锁时,不考虑等待队列中线程的顺序,新到来的线程有可能直接获取到锁,即使等待队列中有其他线程等待时间更长。
- ReentrantLock:默认是非公平锁,但可以通过构造函数设置为公平锁,公平锁会按照线程在等待队列中的顺序分配锁,减少线程饥饿现象。
- 锁的可中断性:
- synchronized关键字:获取锁的过程是不可中断的,一旦线程进入等待获取锁的状态,除非获取到锁或者发生异常,否则不会被中断。
- ReentrantLock:提供了
lockInterruptibly()
方法,允许线程在等待锁的过程中被中断,通过这种方式可以更好地控制线程的执行流程。
- 锁的绑定条件:
- synchronized关键字:与对象的内置锁绑定,一个对象只有一把锁,只能通过
Object
的wait()
、notify()
和notifyAll()
方法进行线程间通信。 - ReentrantLock:可以绑定多个
Condition
对象,每个Condition
对象可以实现不同的等待和唤醒策略,实现更灵活的线程间同步和通信。
- synchronized关键字:与对象的内置锁绑定,一个对象只有一把锁,只能通过
- 性能方面:
- 在JDK早期版本中,
synchronized
的性能相对较差,因为它是重量级锁,涉及到操作系统内核态和用户态的切换。随着JDK的发展,synchronized
进行了很多优化,如偏向锁、轻量级锁等,性能有了很大提升。 - ReentrantLock:在高竞争环境下,
ReentrantLock
的性能可能优于synchronized
,因为它可以通过设置公平锁、使用非公平锁的优化策略等方式来提高性能。但在低竞争环境下,synchronized
的性能可能更好,因为它的使用更简单,开销更小。
- 在JDK早期版本中,