目录
一、核心作用
二、实现原理:基于"对象锁"
三、使用方式
四、锁的优化
五、优缺点
六、总结
synchronized
是 Java 中用于解决多线程并发安全问题的核心关键字,它的主要作用是实现线程间的同步,确保多个线程在访问共享资源时的安全性。
一、核心作用
- 保证原子性
被synchronized
修饰的代码块或方法,在同一时间只能被一个线程执行,确保代码块内的操作不会被其他线程中断,从而保证操作的原子性(不可分割)。 - 保证可见性
线程释放锁时,会将共享变量的最新值刷新到主内存;线程获取锁时,会从主内存重新读取共享变量的值,避免线程使用"过期"数据。 - 保证有序性
通过限制线程执行顺序,间接避免了指令重排序导致的并发问题(类似"天然的内存屏障"效果)。
二、实现原理:基于"对象锁"
synchronized
的核心是"锁",Java 中任何对象都可以作为锁(内置锁/监视器锁),其实现依赖于 JVM 中的 对象头(Mark Word) 和 监视器(Monitor):
- 对象头:存储对象的锁状态(无锁、偏向锁、轻量级锁、重量级锁),JVM 通过更新对象头的标志位来实现锁的获取和释放。
- 监视器(Monitor):一种同步工具,包含等待队列(存放阻塞的线程)和持有线程等信息,确保同一时间只有一个线程能持有锁。
当线程进入 synchronized
代码时,会尝试获取锁(修改对象头的锁状态);执行完毕后释放锁,其他线程才能竞争锁。
三、使用方式
1.修饰实例方法
锁对象是当前实例(this
),多个线程访问同一个实例的该方法时会同步,访问不同实例则不会。
public synchronized void doSomething() {// 同步代码
}
2.修饰静态方法
锁对象是当前类的 Class
对象(全局唯一),所有线程访问该静态方法时都会同步,无论实例是否相同。
public static synchronized void staticMethod() {// 同步代码
}
3.修饰代码块
手动指定锁对象(可自定义对象),灵活性更高,能缩小同步范围以减少性能开销。
public void method() {// 非同步代码synchronized (lockObject) { // lockObject 可以是任意对象// 同步代码块}// 非同步代码
}
四、锁的优化
java 6
之后 JVM 对 synchronized
进行了多次优化,使其性能大幅提升:
- 偏向锁
适用于单线程反复获取锁的场景。当线程第一次获取锁时,标记对象头为"偏向模式",记录线程 ID,后续该线程可直接进入同步代码,无需竞争。 - 轻量级锁
适用于多线程交替执行同步代码的场景。线程获取锁时,通过 CAS 操作在栈帧中创建锁记录并修改对象头,避免重量级锁的内核态操作。 - 重量级锁
适用于多线程同时竞争锁的场景。此时会关联监视器(Monitor),未获取锁的线程会进入阻塞状态(CPU 开销较大)。 - 自适应自旋
当线程获取轻量级锁失败时,不会立即阻塞,而是自旋重试(空循环),JVM 会根据历史重试成功率动态调整自旋次数。
五、优缺点
- 优点:
简单易用,无需手动释放锁;JVM 自动管理锁的升级和释放,安全性高;在低并发场景下性能优异。 - 缺点:
重量级锁会导致线程阻塞/唤醒(内核态操作),高并发下性能可能下降;锁的释放由 JVM 自动完成,无法手动干预(如设置超时)。
六、总结
synchronized
是 Java 并发编程的基础,通过"对象锁"机制保证了原子性、可见性和有序性。其底层实现经历了从重量级锁到偏向锁、轻量级锁的优化,理解 synchronized
的工作原理。
下一篇会详细介绍synchronized
的实现原理,这里简单的了解一下synchronized
的理解以及作用