synchronized关键字实现锁机制原理
- Java对象头:在HotSpot虚拟机中,对象在内存中的布局分为对象头、实例数据和对齐填充三部分。对象头又包含两部分信息,一部分用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志等,这部分数据长度在32位和64位的虚拟机中分别为32bit和64bit,官方称它为“Mark Word”;另一部分是类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。
- Monitor(监视器):Monitor可以理解为一个同步工具或一种同步机制,每一个Java对象都可以关联一个Monitor对象。当一个线程访问同步代码块或方法时,它首先尝试获取对象的Monitor。Monitor有一个计数器,当计数器为0时,表示该Monitor未被占用,线程可以获取并将计数器设置为1,表明该Monitor已被占用。当其他线程尝试获取该Monitor时,发现计数器不为0,则会进入等待队列。当持有Monitor的线程执行完同步代码块或方法后,会将计数器减为0,释放Monitor,等待队列中的线程可以竞争获取Monitor。
synchronized在不同场景下的实现方式
- 修饰实例方法
- 原理:当一个实例方法被synchronized修饰时,锁的对象就是调用该方法的实例对象。此时,该实例对象的Monitor会被获取。线程进入方法时获取Monitor,退出方法时释放Monitor。
- 示例代码:
public class SynchronizedExample {
public synchronized void instanceMethod() {
// 同步代码
}
}
- 修饰静态方法
- 原理:静态方法属于类,当一个静态方法被synchronized修饰时,锁的对象是该类的Class对象。因为Class对象在JVM中是唯一的,所以对该静态方法的同步访问会基于这个唯一的Class对象的Monitor。
- 示例代码:
public class SynchronizedStaticExample {
public static synchronized void staticMethod() {
// 同步代码
}
}
- 修饰代码块
- 原理:当synchronized修饰代码块时,需要指定一个锁对象。线程进入代码块前获取指定锁对象的Monitor,离开代码块时释放Monitor。
- 示例代码:
public class SynchronizedBlockExample {
private final Object lock = new Object();
public void blockMethod() {
synchronized (lock) {
// 同步代码
}
}
}