
scala 的 `synchronized` 并非语法关键字,而是 `anyref` 上定义的普通方法,支持显式锁对象、隐式 `this` 锁及中缀调用形式,三者语义一致但锁作用域和可读性不同。
在 Scala 中,synchronized 是 AnyRef(即 JVM 中的 java.lang.Object)的一个实例方法,其签名等价于:
final def synchronized[T](body: => T): T
这意味着它本质上是“对当前对象加锁后执行代码块”,而非 Java 中的 synchronized 语句(后者是 JVM 指令级语法)。因此,所有 synchronized 调用最终都归结为 对某个具体对象执行 monitor enter/exit —— 这正是 JVM 同步的基础。
三种常见写法及其等价关系
| 写法 | 示例 | 实际锁对象 | 说明 |
|---|---|---|---|
| 隐式 this 锁 | synchronized { ... } | 当前 this 实例 | 等价于 this.synchronized { ... },适用于保护本对象内部状态 |
| 显式对象锁 | lock.synchronized { ... } | lock 实例(如 new Object()) | 推荐方式:避免锁粒度粗、防止外部误锁 this,提升并发安全性 |
| 中缀调用(省略点) | lock synchronized { ... } | lock 实例 | Scala 中缀语法糖,仅当方法名不含参数且为单参数时允许省略 . 和括号;语义完全等价于 lock.synchronized { ... } |
✅ 所有形式均调用同一方法,底层行为完全一致:JVM 对指定对象执行 monitorenter/monitorexit。
正确实践示例
class Counter {
private val lock = new Object() // 专用锁对象,避免暴露 this
private var count = 0
def increment(): Unit = lock.synchronized {
count += 1
}
// 等价写法(不推荐用于生产环境,易引发锁竞争)
def unsafeIncrement(): Unit = synchronized {
count += 1 // 锁住 this,可能被其他 public 方法意外阻塞
}
}⚠️ 注意事项
- ❌ Object synchronized { ... } 是错误写法(除非 Object 是变量名):Object 是 Scala 的伴生对象,不可实例化,不能作为锁;若误写,编译器会报错 value synchronized is not a member of object Object。
- ✅ 锁对象应为私有、不可变、无业务含义的实例(如 private val lock = new Object()),避免使用 this、字符串字面量或可变集合——它们可能导致锁泄露或意外争用。
- ? 查阅权威文档:
- Scala Language Specification §6.12.3 Method Calls(中缀调用规则)
- Scala Standard Library API: AnyRef#synchronized
- JVM 规范 §6.5:monitorenter / monitorexit 指令语义
总结:synchronized 在 Scala 中是统一的方法调用机制,选择 lock.synchronized 是最佳实践;中缀写法仅为语法糖,不应影响逻辑理解;关键在于明确锁对象、控制锁粒度、杜绝锁污染。










