由于不当的执行顺序导致的死锁
为了保证线程的安全,我们引入了加锁机制,但是如果不加限制的使用加锁,就有可能会导致顺序死锁(Lock-Ordering Deadlock)。上篇文章我们也提到了在线程词中因为资源的不足而导致的资源死锁(Resource 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,从而保证同一时间只有一个线程能够运行内部的方法,从而保证了任务的执行而不产生死锁。
本文的例子可以参考https://github.com/ddean2009/learn-java-concurrency/tree/master/accountTransferLock
更多精彩内容且看:
- 区块链从入门到放弃系列教程-涵盖密码学,超级账本,以太坊,Libra,比特币等持续更新
- Spring Boot 2.X系列教程:七天从无到有掌握Spring Boot-持续更新
- Spring 5.X系列教程:满足你对Spring5的一切想象-持续更新
- java程序员从小工到专家成神之路(2020版)-持续更新中,附详细文章教程
更多内容请访问 flydean的博客
由于不当的执行顺序导致的死锁相关推荐
- 线上MySQL死锁分析——索引设置不当导致的死锁
文章目录 1. 背景 2. MySQL InnoDB的锁机制 2.1 MySQL中的锁类型 2.2 行锁的加锁规则 2.3 死锁检测机制 3. 本文案例分析 3.1 分析InnoDB status日志 ...
- MySQL 5.6.35 索引优化导致的死锁案例解析
一.背景 随着公司业务的发展,商品库存从商品中心独立出来成为一个独立的系统,承接主站商品库存校验.订单库存扣减.售后库存释放等业务.在上线之前我们对于核心接口进行了压测,压测过程中出现了 MySQL ...
- 故障分析 | 记一次 MTS 并行复制导致的死锁排查
作者:刘开洋 爱可生交付服务团队北京 DBA,对数据库及周边技术有浓厚的学习兴趣,喜欢看书,追求技术. 本文来源:原创投稿 *爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源 ...
- Jmeter组件执行顺序与作用域
一.Jmeter重要组件: 1)配置元件---Config Element: 用于初始化默认值和变量,以便后续采样器使用.配置元件大其作用域的初始阶段处理,配置元件仅对其所在的测试树分支有效,如,在同 ...
- Spring Aop 常见注解和执行顺序
欢迎关注方志朋的博客,回复"666"获面试宝典 来源:juejin.cn/post/7062506923194581029 Spring 一开始最强大的就是 IOC / AOP 两 ...
- jmeter 线程执行顺序_面试官让我说出8种线程顺序执行的方法!我懵了
https://www.cnblogs.com/wenjunwei/p/10573289.html 一.前言 本文使用了8种方法实现在多线程中让线程按顺序运行的方法,涉及到多线程中许多常用的方法,不止 ...
- aspx页面事件执行顺序
一.详细版 l 初始化 ² 当页面被提交请求第一个方法永远是构造函数.您可以在构造函数里面初始一些自定义属性或对象,不过这时候因为页面还没有被完全初始化所以多少会有些限制.特别地,您需要使用HttpC ...
- SQL语句中各个部分的执行顺序(转)
原文链接:http://www.tuicool.com/articles/fERNv2 写在前面的话:有时不理解SQL语句各个部分执行顺序,导致理解上出现偏差,或者是书写SQL语句时随心所欲,所以有必 ...
- iOS tableview的常用delegate和dataSource执行顺序
在这次项目中遇到了一个特别奇葩的问题:表视图创建的cell在7以上的系统能正常运行显示,在模拟器上就不能正常实现......为解决这个问题,纠结了好久...... 对在7系统上不显示的猜测: 用mas ...
最新文章
- Vue Router路由嵌套
- 点在多边形内算法,C#判断一个点是否在一个复杂多边形的内部
- 阮一峰es6电子书_ES6理解进阶【大前端高薪训练营】
- sublime text3安装
- md5 java代码_JAVA简单实现MD5注册登录加密实例代码
- 国际C语言混乱代码大赛
- java的queue类,java集合类深入分析之Queue篇
- RuntimeError: output with shape [4, 1, 512, 512] doesn‘t match the broadcast shape[4, 4, 512, 512]
- 电子统计台账:垂直流水账格式数据的导入
- Quantum Espresso安装
- 学习之 “Spark的安装配置”
- STM32F103基于HAL库移植uC/OS-III
- exp oracle 904,EXP-00008: ORACLE error 904 encountered的解决方法
- 影片剪辑app android,4款经典的手机影片剪辑App
- 【读书笔记】-最优状态估计 Optimal State Estimation Kalman, H,, and Nonlinear Approaches 【Dan Simon】
- 【极富参考价值!】第1章 ClickHouse 简介《ClickHouse 企业级大数据分析引擎实战》...
- PowerManagerService分析-updatePowerStateLocked方法
- 一种高性能计算机网络控制技术,一种高性能流量计算机的研制
- 判天地之美,析万物之理
- PyGmae:有限状态机实践(十四)