Java 同步机制 synchronized

Java 同步机制 synchronized
Liuxz在并发程序中,只有当多个线程争抢同一个锁对象时,才能实现对临界资源(共享资源)的同步控制。如果锁对象不同,多个线程会各自持有不同的锁,无法相互限制,会导致并发安全问题(如数据不一致、重复操作等)。
核心逻辑:锁的 “互斥性” 依赖于 “同一把锁”
- 相同锁:多个线程会排队等待获取这把锁,同一时间只有一个线程能执行同步代码(实现 “互斥”),从而保证共享资源的安全。
- 不同锁:每个线程可以同时获取自己的锁,同步代码会被并发执行,无法保证共享资源的安全。
一、核心概念定义
1. synchronized 关键字
本质:Java 提供的用于实现线程同步的核心关键字,是实现 “互斥” 和 “原子性” 的基础工具。
作用:保证多个线程对共享资源的访问是 “串行执行” 的,避免并发安全问题(如数据不一致、重复操作)。
适用场景:可作用于两个维度:
修饰方法:生成 “同步函数”;
修饰代码块:生成 “同步代码块”。
2. 同步函数
- 本质:被 synchronized 关键字修饰的方法,是 synchronized 的一种具体应用结果。
核心特性:
同步范围:默认同步整个方法体,线程进入方法时获取锁,退出方法时释放锁;
锁对象固定:由方法类型(静态 / 非静态)决定,不可自定义。
二、synchronized 与同步函数的关系(核心区分)
1. 包含与被包含关系
- synchronized 是 “工具”,同步函数是 “工具的产物”:
只有用 synchronized 修饰方法,才能生成同步函数;没有 synchronized,就不存在 “同步函数” 这一概念。
2. 关键区别(表格对比)
| 对比维度 | synchronized 关键字 | 同步函数 |
| 概念本质 | 同步工具(关键字) | 被工具修饰的方法(应用结果) |
| 作用范围 | 灵活:可修饰方法、可修饰代码块 | 固定:仅覆盖整个方法体 |
| 锁对象灵活性 | 修饰代码块时可自定义锁对象(如 new Object()) | 锁对象固定(非静态→this,静态→类名.class) |
| 核心能力 | 提供同步机制的 “基础能力” | 借助 synchronized 实现 “方法级同步” |
三、同步函数的分类与锁对象规则
同步函数按 “是否静态” 分为两类,核心区别在于锁对象不同,这是保证同步的关键。
1. 非静态同步函数
锁对象:当前对象实例(this),即调用该方法的对象。
等价转换:非静态同步函数本质是 “用 this 作为锁的同步代码块”,示例如下:
1 |
|
- 适用场景:多线程操作 “同一对象实例的共享资源”(如同一售票窗口的票)。
2. 静态同步函数
锁对象:当前类的字节码对象(类名.class),一个类只有一个字节码对象,全局唯一。
等价转换:静态同步函数本质是 “用 类名.class 作为锁的同步代码块”,示例如下:
1 |
|
- 适用场景:多线程操作 “类级别的共享资源”(如静态变量、全局配置)。
四、同步的核心原则(保证线程安全的关键)
1. 锁对象一致性原则
核心逻辑:多个线程要实现同步(互斥访问共享资源),必须争抢 “同一把锁”。
若锁对象相同:线程排队获取锁,同一时间只有一个线程执行同步代码,安全;
若锁对象不同:线程各自持有不同锁,同步代码并发执行,存在安全问题(如数据错误)。
2. 不同场景的锁对象匹配示例
| 场景 | 同步函数类型 | 同步代码块需用的锁对象 | 目的 |
| 非静态同步函数 + 同步代码块 | 非静态同步函数 | this | 保证同一对象的操作互斥 |
| 静态同步函数 + 同步代码块 | 静态同步函数 | 类名.class | 保证类级别的操作互斥 |
五、常见误区与注意事项
- 误区 1:同步函数等同于 synchronized
错误:同步函数是 synchronized 的应用之一,synchronized 还能修饰代码块,两者不是同一概念。
- 误区 2:静态同步函数的锁是 this
错误:静态方法属于 “类”,不属于 “对象”,锁对象是 类名.class,而非 this(this 仅存在于非静态方法中)。
- 注意事项:同步范围并非越大越好
同步函数同步整个方法体,若方法中包含非共享资源操作,会导致 “锁粒度太大”,降低并发效率;此时建议用 synchronized 代码块,只同步 “共享资源相关的核心代码”。




