synchronized通过互斥执行、内存可见、指令有序三重保障解决线程安全问题,将count++等复合操作封装为原子临界区,并依修饰目标(实例/静态方法或代码块)采用不同锁对象,同时协同jmm确保可见性与有序性。

synchronized 通过“互斥执行 + 内存可见 + 指令有序”三重保障,让多线程对共享资源的操作从“可能交错”变成“强制排队”,从而解决线程安全问题。
它怎么堵住竞态条件的漏洞
像 count++ 这类操作,表面一行代码,底层其实是“读值→加1→写回”三步。多个线程同时执行时,容易出现:线程A读到 count=5,还没来得及写回;线程B也读到 count=5,各自加1后都写回6——结果只加了1次,而不是2次。synchronized 把这三步打包成一个不可分割的临界区,确保任一时刻最多一个线程在执行,彻底切断交叉执行路径。
三种用法对应不同“守门人”
- 修饰实例方法:锁是 this(当前对象)。同一对象的多个同步方法互斥,不同对象之间不干扰。适合保护单个对象内部状态,比如账户余额、订单状态。
- 修饰静态方法:锁是 类.class(如 Account.class)。所有实例共用一把锁。适合保护全局资源,比如单例初始化、应用级计数器。
- 修饰同步代码块:显式指定锁对象,例如 synchronized(lockObj)。粒度最细,能避免锁整个方法带来的性能浪费,也便于统一锁对象防死锁(推荐用 private final Object lock = new Object())。
它不只是“排队”,还管“记账”和“传话”
synchronized 不仅限制执行顺序,还协同 Java 内存模型(JMM)工作:
- 可见性:线程释放锁前,会把本地内存中所有修改强制刷回主内存;获取锁时,会清空本地副本,重新从主内存加载最新值。这样其他线程不会看到过期数据。
- 有序性:禁止编译器和处理器对同步块内的指令做重排序,也防止块内代码“溢出”到块外执行,保证逻辑顺序与代码书写一致。
哪些坑要特别注意
- 别用 String、Integer 等可变引用作锁对象——它们可能被字符串常量池复用或自动装箱替换,导致实际锁对象不一致,同步失效。
- 避免在 高频循环里锁整个方法,容易造成线程长时间排队,成为性能瓶颈。
- 同步块里 别调用外部不可控方法(比如网络请求、第三方回调),否则锁持有时间不可控,可能引发超时或死锁。
- volatile 不能替代 synchronized:volatile 只保可见性和禁止重排,不保复合操作原子性(i++ 依然错)。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











