
本文详解 Java synchronized 的锁作用域本质:它仅作用于被显式指定的单个对象实例的内在锁(intrinsic lock),绝不会递归或隐式地锁定该对象内部持有的其他引用对象;理解这一点是避免并发误用和设计正确线程安全类的关键。
本文详解 java `synchronized` 的锁作用域本质:它仅作用于被显式指定的**单个对象实例的内在锁(intrinsic lock)**,绝不会递归或隐式地锁定该对象内部持有的其他引用对象;理解这一点是避免并发误用和设计正确线程安全类的关键。
在 Java 并发编程中,一个常见误区是认为 synchronized(this) 会“连带”锁定当前对象所引用的全部成员变量(如 ServerState state)。这是完全错误的。 synchronized 操作的对象始终是且仅是括号内表达式求值所得的那个对象实例——即它的内在锁(monitor lock)。JVM 不会、也不能感知该对象内部字段的语义或生命周期,更不会自动加锁其引用的其他对象。
以下代码清晰验证了这一核心原则:
class UserImpl {
private final ServerState state;
UserImpl(ServerState state) { this.state = state; }
// 仅锁定 UserImpl 实例本身,与 state 对象无关
public synchronized void setStateString(String s) {
state.addString(s); // 此处对 state 的操作完全不受此 synchronized 保护!
}
}
class AdminImpl {
private final ServerState state;
AdminImpl(ServerState state) { this.state = state; }
// 仅锁定 AdminImpl 实例本身,与 state 对象无关
public synchronized void setStateString(String s) {
state.addString(s);
}
}
如上所示,UserImpl.setStateString() 和 AdminImpl.setStateString() 分别使用 synchronized(this),意味着它们各自锁定的是 不同的对象实例(user 和 admin),而共享的 ServerState 实例 state 并未被任何 synchronized 块覆盖。因此,两个线程可同时进入各自的 setStateString 方法,并并发调用 state.addString(s) —— 这正是竞态条件(race condition)的根源。
运行示例程序后输出 "admin"(而非预期的 "useradmin"),正是因为 addString 方法中读取 state、休眠、再拼接赋值的三步操作未被原子化保护,导致线程交错执行。
✅ 正确做法:将同步粒度精准锚定在需要保护的共享状态上。本例中,真正需互斥访问的是 ServerState.state 字段,因此应直接同步 ServerState 实例:
class ServerState {
private String state = "";
// ✅ 正确:同步 ServerState 实例,保护其内部状态
public synchronized void addString(String s) {
state = state + s;
}
}
或者使用显式锁对象(推荐用于细粒度控制):
class ServerState {
private final Object lock = new Object();
private String state = "";
public void addString(String s) {
synchronized (lock) { // ✅ 锁定专用对象,避免锁泄露
state = state + s;
}
}
}
⚠️ 注意事项:
- synchronized(this) 在非 final 字段场景下易引发锁泄露(如 this 被外部持有并用于其他同步),应优先考虑私有锁对象;
- 若多个类需协同保护同一共享资源(如本例的 ServerState),必须统一使用同一个锁对象(如 state 实例本身或其私有锁),而非各自 synchronized(this);
- volatile 仅保证可见性,不提供原子性,无法替代同步机制处理复合操作(如 read-modify-write)。
总结:Java 同步的本质是对象级锁,而非引用图遍历锁。开发者必须主动识别共享状态的归属边界,并显式选择恰当的锁目标——这是构建可靠并发程序不可绕过的基石。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











