Java中的synchronized
关键字是用于实现线程同步的一种机制,其底层原理主要基于 monitor监视器锁。每个 Java 对象都有一个与之关联的 monitor 对象,当一个线程访问同步代码块或方法时,它需要获取该对象的 monitor 锁;如果其他线程尝试获取同一个对象的 monitor 锁,则会阻塞直到当前线程释放锁。
具体来说,synchronized 的实现依赖于对象头(Object Header)中的锁状态标志位和指向锁记录(Lock Record)的指针。对象头分为三部分:Mark Word、实例数据和对齐填充。当线程进入同步代码块时,会执行 monitorenter 指令,这将检查对象头中的锁状态标志位,如果为 false,则表示没有线程持有该对象的锁,此时线程会进入等待状态并尝试获取锁;如果为 true,则表示有线程已经持有该对象的锁,当前线程则会阻塞直到锁被释放。
在JDK 5 版本之前,synchronized只有重量级锁。但是,在JDK
5 版本之后对 synchronized 进行了多个重大优化,引入了轻量级锁、偏向锁等技术来减少锁的竞争开销。这些优化包括:
- 轻量级锁:在多线程竞争不激烈的场景下,使用更小的字节码指令代替重量级的互斥量。
- 偏向锁:当只有一个线程持有锁时,可以减少线程切换的开销。
- 自适应自旋:根据前一次进入锁的时间动态调整自旋次数,以提高效率。
总的来说,synchronized 的底层原理是通过对象头中的锁状态标志位和指向锁记录的指针来实现的,并且依赖于操作系统的互斥原语Mutex来保证线程安全。随着版本的演进,JVM 对 synchronized 进行了多次优化,以提升性能和减少不必要的开销。