浅谈Java由于不当的执行顺序导致的死锁

 更新时间:2021年06月01日 12:55:16   作者:flydean  
为了保证线程的安全,我们引入了加锁机制,但是如果不加限制的使用加锁,就有可能会导致顺序死锁(Lock-Ordering Deadlock)。本文将会讨论一下顺序死锁的问题。

我们来讨论一个经常存在的账户转账的问题。账户A要转账给账户B。为了保证在转账的过程中A和B不被其他的线程意外的操作,我们需要给A和B加锁,然后再进行转账操作, 我们看下转账的代码:

public void transferMoneyDeadLock(Account from,Account to, int amount) throws InsufficientAmountException {
    synchronized (from){
        synchronized (to){
            transfer(from,to,amount);
        }
    }
}

private void transfer(Account from,Account to, int amount) throws InsufficientAmountException {
    if(from.getBalance() < amount){
        throw new InsufficientAmountException();
    }else{
        from.debit(amount);
        to.credit(amount);
    }
}

看起来上面的程序好像没有问题,因为我们给from和to都加了锁,程序应该可以很完美的按照我们的要求来执行。

那如果我们考虑下面的一个场景:

A:transferMoneyDeadLock(accountA, accountB, 20)
B:transferMoneyDeadLock(accountB, accountA, 10)

如果A和B同时执行,则可能会产生A获得了accountA的锁,而B获得了accountB的锁。从而后面的代码无法继续执行,从而导致了死锁。

对于这样的情况,我们有没有什么好办法来处理呢?

加入不管参数怎么传递,我们都先lock accountA再lock accountB是不是就不会出现死锁的问题了呢?

我们看下代码实现:

private void transfer(Account from,Account to, int amount) throws InsufficientAmountException {
    if(from.getBalance() < amount){
        throw new InsufficientAmountException();
    }else{
        from.debit(amount);
        to.credit(amount);
    }
}

public void transferMoney(Account from,Account to, int amount) throws InsufficientAmountException {

    int fromHash= System.identityHashCode(from);
    int toHash = System.identityHashCode(to);

    if(fromHash < toHash){
        synchronized (from){
            synchronized (to){
                transfer(from,to, amount);
            }
        }
    }else if(fromHash < toHash){
        synchronized (to){
            synchronized (from){
                transfer(from,to, amount);
            }
        }
    }else{
        synchronized (lock){
        synchronized (from) {
            synchronized (to) {
                transfer(from, to, amount);
            }
            }
        }
    }
}

上面的例子中,我们使用了System.identityHashCode来获得两个账号的hash值,通过比较hash值的大小来选定lock的顺序。

如果两个账号的hash值恰好相等的情况下,我们引入了一个新的外部lock,从而保证同一时间只有一个线程能够运行内部的方法,从而保证了任务的执行而不产生死锁。

以上就是浅谈Java由于不当的执行顺序导致的死锁的详细内容,更多关于Java由于不当的执行顺序导致的死锁的资料请关注脚本之家其它相关文章!

相关文章

  • springboot集成swagger过程解析

    springboot集成swagger过程解析

    这篇文章主要介绍了springboot集成swagger过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-01-01
  • Mybatis 批量更新实体对象方式

    Mybatis 批量更新实体对象方式

    这篇文章主要介绍了Mybatis 批量更新实体对象方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-11-11
  • Java BeanUtils.copyProperties的详解

    Java BeanUtils.copyProperties的详解

    这篇文章主要介绍了Java BeanUtils.copyProperties的详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-08-08
  • Java与Android使用监听者模式示例

    Java与Android使用监听者模式示例

    这篇文章主要为大家介绍了Java与Android使用监听者模式示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-08-08
  • springboot pojo对象日期属性的问题

    springboot pojo对象日期属性的问题

    这篇文章主要介绍了springboot pojo对象日期属性的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10
  • Zookeeper Curator使用介绍

    Zookeeper Curator使用介绍

    curator是Netflix公司开源的⼀套Zookeeper客户端框架,和ZKClient⼀样,Curator解决了很多Zookeeper客户端非常底层的细节开发⼯作,包括连接重连,反复注册Watcher和NodeExistsException异常等,是最流行的Zookeeper客户端之⼀
    2022-09-09
  • Java运算符>、>>、>>>三者的区别

    Java运算符>、>>、>>>三者的区别

    这篇文章主要介绍了Java运算符>、>>、>>>三者的区别,做了一个简单的对比,并用实例说明,需要的朋友可以参考下
    2014-06-06
  • Java中NoClassDefFoundError 和 ClassNotFoundException的区别

    Java中NoClassDefFoundError 和 ClassNotFoundException的区别

    Java中NoClassDefFoundError和ClassNotFoundException的区别,从类继承层次上来看,ClassNotFoundException是从Exception继承的,所以ClassNotFoundException是一个检查异常。具体详情需要的朋友可以参考下面文章内容
    2022-06-06
  • 使用Mybatis遇到的坑之Integer类型参数的解读

    使用Mybatis遇到的坑之Integer类型参数的解读

    这篇文章主要介绍了使用Mybatis遇到的坑之Integer类型参数的解读,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-03-03
  • Java中csv文件读写超详细分析

    Java中csv文件读写超详细分析

    CSV是一种通用的、相对简单的文件格式,其文件以纯文本形式存储表格数据,下面这篇文章主要给大家介绍了关于Java中csv文件读写分析的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-05-05

最新评论