🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
同步锁使用的弊端:当线程任务中出现了多个同步(多个锁)时,如果同步中嵌套了其他的同步。这时容易引发一种现象:程序出现无限等待,这种现象我们称为死锁。这种情况能避免就避免掉。 ~~~ synchronzied(A锁){ synchronized(B锁){ } } ~~~ 这是一个关于死锁的问题,代码如下: ![](https://box.kancloud.cn/d22f052fcdb40f2d81293135bf91ddd0_778x214.png) 很明显,这段代码在多线程情况下,会产生死锁: 假设线程1 做的操作是账户A给账户B转账, 先锁住了A账户, 接下来试图申请B账户的锁, 与此同时线程2 在从 账户B给账户A 转账, 先锁住了B账户的锁, 接下来试图申请A账户的锁。 **两个线程各自持有资源, 然后等待获取对方的资源, 都无法执行下去, 死锁就出现了。** 怎么写代码才能避免这种死锁呢?下面的代码是一种解决办法: ![](https://box.kancloud.cn/adac181e2a3db692542e12efde50f7a1_769x699.png) 这段代码看起来有点吃力,但是如果你学过操作系统对死锁的处理的话, 就变的很容易。 操作系统中的理论是这样的: 如果有多个线程对多个资源进行访问时, 需要对资源进行排序(排序的方法你自己确定), 然后所有的线程都按同样的次序来访问资源,这样就不会出现环路等待了。 例如有10个线程, 每个都要访问多个资源, 对资源排序以后, 大家都先锁住1号资源进行访问(注意同一时刻,只有一个线程能获得锁, 别的都得等待) 然后是2号, 3号。。。 由于大家访问的次序是一样的, 就不会出现死锁的的情况。 理解了这一点, 对于上面的代码就很容易理解了, 实际就是对Account(账户)进行资源的排序, 通过 Java 内置的方法,得到Hashcode。 然后按顺序访问。 如果fromAccount 比较小, 那就先锁住fromAccount, 然后锁住toAccount, 反过来也是类似。 假设线程1 做的操作是账户A给账户B转账, 先锁住了A账户(假设A的hashcode 比较小), 接下来试图申请B账户的锁, 与此同时线程2 在从 账户B给账户A 转账, 由于A的hashcode 较小, 这个线程也试图先申请A的锁, 当然它申请不到, 因为已经被线程1持有了, 线程2只能等待 等到线程1完成操作以后, 线程2才能继续, 死锁就消除了。 如果两个账号的hashCode 相等怎么办, 没办法,只好引用一个第三方的锁了解决了, 这就是上述代码的else 分支 synchronized(lock) .