CoderEden
Faust's Pact · 浮士德之契

每一次 synchronized,都是一次签约

Every `synchronized` is a Pact

2026年4月21日 · 2 min read · 约 2 分钟

Where does the lock actually live, and what does it carry?

锁到底存在哪里?锁里面会存储什么信息?

— 自问于《Java 并发艺术》第二章页边

一、签约的时候不讨账

我在读《Java 并发艺术》的第二章。读到第三页,手边那支笔停住了。

我从前以为 synchronized 是一个关键字,现在才看清它其实是一份合同——每次我在方法前面按下这九个字母时,JVM 就从抽屉里抽出一张条款翻到我面前:

public synchronized void transfer(Account to, long amount) { ... }

我签了名。程序跑了起来。一切顺利。

Mephistopheles 从不在签约当夜讨债。他等我写完单元测试、合并到主分支、推上生产环境——然后才打开账本。

二、四张合同,利息递增

账本上其实有四张条款,按我被打扰的频率依次兑现:

无锁——谁都没来,我什么也不用付。

偏向锁。第一位线程路过,我偏心地把它的 ID 刻在对象头的 Mark Word 上:“以后还是你来,我认你了。“——代价几乎为零,除非有第二位访客。

轻量级锁。第二位访客出现。偏心的约定需要撤销,新约定建立:在线程的栈帧里建一份锁记录(Displaced Mark Word),用 CAS 把对象头替换为指向这份记录的指针。两位线程开始自旋——我在旋转的过程中烧 CPU 做代价。

重量级锁。自旋也抢不到。于是整条约定升级:OS 级 monitor 介入,抢不到的线程被挂起阻塞,持有者释放锁后再唤醒它们。此时我付出的是响应时间——线程上下文切换、操作系统调度、一切现代计算机在纸面上承诺过要很快的东西。

锁可以升级,不能降级。JVM 这样写进规则——凡签下的账,不许反悔。

三、我读不懂第三条脚注

书里讲偏向锁撤销那一节时,我停在了页边写下一句话:“这一块还是不清楚,得上网再看看。”

然后我笑了。

浮士德在签约之前问过许多问题,但那张羊皮卷展开的时候,他已经不再仔细读。一整本 JVM 规范里藏着多少这样的脚注、这样的”需要时再查”?每一个工程师的 synchronized 背后,都是这样一份没有被完整读完的合同。

但我仍然签。明天还签。

代码合上,书合上。窗外是凌晨两点的北京——恰如 Walpurgisnacht 刚刚开始的那一刻。

Zwei Seelen wohnen, ach! in meiner Brust.
两个灵魂啊,居于我胸中。