You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何《并发编程实战》Listing10.3中identityHashCode死锁安全实现有效?

关于《并发编程实战》Listing10.3锁排序方案的疑问解答

一、如何保证不同线程中对应Account的identityHashCode大小关系一致?

首先明确:System.identityHashCode(Object)返回的是对象的内存身份哈希值,仅对同一个对象实例,所有线程调用该方法返回的结果固定;但对于两个equals相等但实例不同的Account对象(如akk1Thread1=new Account(1)和akk1Thread2=new Account(1)),它们是完全独立的对象,identityHashCode可能完全不同,此时无法保证不同线程中对应业务实体的哈希值大小关系一致。

这种场景下,依赖identityHashCode的锁排序逻辑会直接失效:线程A中myAccount(akk1Thread1)的哈希值可能大于yourAccount(akk2Thread1),而线程B中yourAccount(akk1Thread2)的哈希值可能小于myAccount(akk2Thread2),导致两个线程的锁获取顺序完全相反,死锁风险依然存在。

正确的解决方式是基于Account的业务唯一标识(如账号ID)进行排序,而非对象本身的身份哈希。比如每个Account都有一个id字段,通过比较id的大小来决定锁的获取顺序:

public void transferMoney(Account from, Account to, int amount) throws InterruptedException {
    Account first = from.id < to.id ? from : to;
    Account second = from.id < to.id ? to : from;
    synchronized (first) {
        synchronized (second) {
            from.debit(amount);
            to.credit(amount);
        }
    }
}

这样无论线程拿到的是哪个实例,只要是同一个业务账号(id相同),排序逻辑就完全一致,锁的获取顺序不会混乱。

二、该示例是否仅在应用存在全局Account缓存时才有效?

是的,Listing10.3的锁排序方案**必须依赖“同一个业务账号对应唯一的Account对象实例”**的前提,也就是应用存在全局缓存(比如将Account实例存入全局Map,通过账号ID获取)或者对象池。

只有在这种场景下,线程A和线程B操作的同一个业务账号对应的是同一个Account实例,它们的System.identityHashCode值完全相同,锁的排序逻辑才能保证一致,避免死锁。如果没有全局缓存,每个线程自行创建Account实例,哪怕equals相等,只要是不同对象,identityHashCode就可能不同,锁排序逻辑会直接失效,死锁依然可能发生。


内容的提问来源于stack exchange,提问作者Belenot

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 09:15:05