
scala 的 `synchronized` 并非关键字,而是 `anyref` 类定义的普通方法,支持点号调用、中缀调用和作用于 `this` 的隐式调用,三者语义一致但锁对象不同——关键在于调用主体(即锁实例)的选择。
在 Scala 中,synchronized 是 AnyRef(即 Java Object 的别名)上的一个实例方法,其签名等价于:
final def synchronized[T](body: => T): T
这意味着它必须被某个对象调用,而该对象本身即为同步所依赖的监视器锁(monitor lock)。因此,所谓“不同用法”,本质是调用主体不同,而非语法糖差异。下面逐一解析常见写法:
✅ 1. 隐式锁:synchronized { ... }(等价于 this.synchronized { ... })
这是最简写法,省略了调用者,默认以当前对象(this)为锁:
class Counter {
private var count = 0
def increment(): Unit = synchronized { count += 1 } // 锁住 this
}⚠️ 注意:若多个线程操作同一个实例,此方式有效;但若并发访问不同实例,则互不阻塞——因为锁对象不同。
✅ 2. 显式对象锁:lock.synchronized { ... }(推荐)
显式创建专用锁对象,避免污染业务对象语义,提升可读性与安全性:
class BankAccount {
private val lock = new Object()
private var balance = 0.0
def deposit(amount: Double): Unit = lock.synchronized {
balance += amount
}
}✅ 优势:锁对象私有、无业务含义,不易被外部误用;适合细粒度控制。
✅ 3. 中缀调用:lock synchronized { ... }(语法糖,完全等价)
Scala 允许单参数方法省略点号和括号(中缀表示法),因此:
lock.synchronized { ... }
// 等价于
lock synchronized { ... }这不是特殊语法,而是 Scala 统一的中缀表达式规则(如 1 + 2 实际是 1.+(2))。它与点号调用在字节码层面完全一致,仅风格差异。
❌ 常见误解澄清
- Object synchronized { ... } ❌ —— 若 Object 是 java.lang.Object.type(伴生对象),它不可实例化,无法作为锁;此写法通常因命名冲突导致编译错误。正确应为 new Object().synchronized { ... } 或使用已声明的锁变量。
- synchronized(Object) ❌ —— 这是 Java 风格误写;Scala 中 synchronized 是方法,不接受参数传入锁对象,锁由调用者决定。
? 核心原则总结
| 写法 | 锁对象 | 是否推荐 | 说明 |
|---|---|---|---|
| synchronized { ... } | this | ⚠️ 谨慎 | 适用于单例或明确需锁住整个实例的场景 |
| lock.synchronized { ... } | 自定义 lock 实例 | ✅ 强烈推荐 | 解耦锁与业务逻辑,线程安全更可控 |
| lock synchronized { ... } | 同上(语法糖) | ✅ 可用 | 纯属风格选择,与点号调用无任何行为差异 |
? 官方依据:Scala Language Specification §6.12.3 Method Calls 明确指出中缀调用是方法调用的语法变体;synchronized 定义见 Scala Standard Library → AnyRef。
实践中,请始终优先使用私有锁对象 + 点号或中缀调用,避免隐式锁带来的耦合风险。锁的本质是 JVM 层面的 monitorenter/monitorexit 指令,Scala 所做只是对 Object 原生能力的安全封装。










