研究僵局–第4部分:修复代码

在这个简短的博客系列的最后BadTransferOperation中,我一直在讨论分析死锁,我将修复BadTransferOperation代码。 如果您看过本系列的其他博客 ,那么您将知道,为了达到这一点,我创建了死锁的演示代码,展示了如何掌握线程转储,然后分析了线程转储,弄清楚发生僵局的位置和方式。 为了节省空间,下面的讨论同时引用了本系列第1部分中的AccountDeadlockDemo类,其中包含完整的代码清单。

教科书中有关死锁的描述通常是这样的:“线程A将获得对象1的锁定,并等待对象2的锁定,而线程B将获得对象2的锁定,同时等待对象1的锁定”。 我以前的博客中显示的堆积,并在下面突出显示,是一个真实的死锁,其他线程,锁和对象陷入了直接,简单,理论上的死锁情况。

Found one Java-level deadlock:
=============================
'Thread-21':waiting to lock monitor 7f97118bd560 (object 7f3366f58, a threads.deadlock.Account),which is held by 'Thread-20'
'Thread-20':waiting to lock monitor 7f97118bc108 (object 7f3366e98, a threads.deadlock.Account),which is held by 'Thread-4'
'Thread-4':waiting to lock monitor 7f9711834360 (object 7f3366e80, a threads.deadlock.Account),which is held by 'Thread-7'
'Thread-7':waiting to lock monitor 7f97118b9708 (object 7f3366eb0, a threads.deadlock.Account),which is held by 'Thread-11'
'Thread-11':waiting to lock monitor 7f97118bd560 (object 7f3366f58, a threads.deadlock.Account),which is held by 'Thread-20'


如果将上面的文本和图像与以下代码相关联,则可以看到Thread-20已锁定其fromAccount对象( fromAccount ),正在等待锁定其toAccount对象(e98)

private void transfer(Account fromAccount, Account toAccount, int transferAmount) throws OverdrawnException {synchronized (fromAccount) {synchronized (toAccount) {fromAccount.withdraw(transferAmount);toAccount.deposit(transferAmount);}}}

不幸的是,由于时序问题, Thread-20无法获得对对象e98的锁定,因为它正在等待Thread-4释放对该对象的锁定。 Thread-4无法释放锁,因为它正在等待Thread-7Thread-7正在等待Thread-11Thread-11正在等待Thread-20释放对对象f58的锁。 这个现实世界的僵局只是教科书描述的一个更复杂的版本。

这段代码的问题是,从下面的代码片段中,您可以看到我正在从Accounts数组中随机选择两个Account对象作为fromAccounttoAccount并将它们锁定。 由于fromAccounttoAccount可以引用accounts数组中的任何对象,这意味着它们以随机顺序被锁定。

Account toAccount = accounts.get(rnd.nextInt(NUM_ACCOUNTS));Account fromAccount = accounts.get(rnd.nextInt(NUM_ACCOUNTS));

因此, 解决方法是对Account对象的锁定方式施加顺序,并且只要顺序一致,任何顺序都可以执行。

private void transfer(Account fromAccount, Account toAccount, int transferAmount) throws OverdrawnException {if (fromAccount.getNumber() > toAccount.getNumber()) {synchronized (fromAccount) {synchronized (toAccount) {fromAccount.withdraw(transferAmount);toAccount.deposit(transferAmount);}}} else {synchronized (toAccount) {synchronized (fromAccount) {fromAccount.withdraw(transferAmount);toAccount.deposit(transferAmount);}}}}

上面的代码显示了此修复程序。 在此代码中,我使用帐号来确保首先锁定具有最高帐号的Account对象,以便永远不会出现以上的死锁情况。

以下代码是此修复程序的完整列表:

public class AvoidsDeadlockDemo {private static final int NUM_ACCOUNTS = 10;private static final int NUM_THREADS = 20;private static final int NUM_ITERATIONS = 100000;private static final int MAX_COLUMNS = 60;static final Random rnd = new Random();List<Account> accounts = new ArrayList<Account>();public static void main(String args[]) {AvoidsDeadlockDemo demo = new AvoidsDeadlockDemo();demo.setUp();demo.run();}void setUp() {for (int i = 0; i < NUM_ACCOUNTS; i++) {Account account = new Account(i, rnd.nextInt(1000));accounts.add(account);}}void run() {for (int i = 0; i < NUM_THREADS; i++) {new BadTransferOperation(i).start();}}class BadTransferOperation extends Thread {int threadNum;BadTransferOperation(int threadNum) {this.threadNum = threadNum;}@Overridepublic void run() {for (int i = 0; i < NUM_ITERATIONS; i++) {Account toAccount = accounts.get(rnd.nextInt(NUM_ACCOUNTS));Account fromAccount = accounts.get(rnd.nextInt(NUM_ACCOUNTS));int amount = rnd.nextInt(1000);if (!toAccount.equals(fromAccount)) {try {transfer(fromAccount, toAccount, amount);System.out.print(".");} catch (OverdrawnException e) {System.out.print("-");}printNewLine(i);}}System.out.println("Thread Complete: " + threadNum);}private void printNewLine(int columnNumber) {if (columnNumber % MAX_COLUMNS == 0) {System.out.print("\n");}}/*** This is the crucial point here. The idea is that to avoid deadlock you need to ensure that threads can't try* to lock the same two accounts in the same order*/private void transfer(Account fromAccount, Account toAccount, int transferAmount) throws OverdrawnException {if (fromAccount.getNumber() > toAccount.getNumber()) {synchronized (fromAccount) {synchronized (toAccount) {fromAccount.withdraw(transferAmount);toAccount.deposit(transferAmount);}}} else {synchronized (toAccount) {synchronized (fromAccount) {fromAccount.withdraw(transferAmount);toAccount.deposit(transferAmount);}}}}}
}

在我的示例代码,死锁的发生是因为时机问题,嵌套的synchronized在我的关键字BadTransferOperation类。 在此代码中, synchronized关键字位于相邻的行上; 但是,最后一点是,值得注意的是, synchronized关键字在代码中的什么位置都没关系(它们不必相邻)。 只要您使用同一线程锁定两个(或更多)不同的监视对象,就会发生排序和死锁。

有关更多信息,请参阅本系列中的其他博客 。

该系列以及其他博客的所有源代码都可以在Github上找到,网址为git://github.com/roghughe/captaindebug.git

参考: 调查死锁-第4部分:来自Captain Debug博客博客的JCG合作伙伴 Roger Hughes 修复代码 。

翻译自: https://www.javacodegeeks.com/2012/11/investigating-deadlocks-part-4-fixing-the-code.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/370433.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

chrome插件2

转自&#xff1a;http://www.codeceo.com/article/15-chrome-extension.html 1. Web Developer 支持Chrome的Web Developer扩展&#xff0c;允许你通过添加一个小工具栏来使用不同的工具。 官方网站&#xff1a;https://chrome.google.com/webstore/detail/web-developer/bfbam…

java月历组件_vue之手把手教你写日历组件

---恢复内容开始---1.日历组件1.分析功能&#xff1a;日历基本功能&#xff0c;点击事件改变日期&#xff0c;样式的改变1.结构分析&#xff1a;html1.分为上下两个部分2.上面分为左按钮&#xff0c;中间内容展示&#xff0c;右按钮下面分为周几展示和日期展示3.基本结构页面ht…

maven project module 依赖项目创建 ---转

一、创建Maven Project 1.右击 --> New --> Other&#xff0c;--> Maven --> Maven Project --> Next 2.如下图&#xff0c;选中Create a simple project --> Next 3.输入Group Id, Artifact Id, Version, Packaging选择pom&#xff0c;因为创建的Maven Pr…

linux常见命令搜集

查找根目录下txt和pdf文件 find / \( -name "*.txt" -o -name "*.pdf" \) -print 正则查找根目录下所有的txt和pdf文件 find / -regex ".*\(\.txt|\.pdf\)$"查找所有非txt文本 find . ! -name "*.txt" -print制定搜索深度 find ~ -max…

需加装饰——装饰模式

装饰模式指的是在不必改变原类文件和使用继承的情况下&#xff0c;动态地扩展一个对象的功能。它是通过创建一个包装对象&#xff0c;也就是装饰来包裹真实的对象。 类图分析 我们先假设一个业务场景&#xff0c;有三种房子需要装修&#xff0c;分别是公寓&#xff0c;木屋和别…

Vue2.0 --- vue-cli脚手架中全局引入JQ

第一步&#xff1a;安装jQuery npm/cmpn方式安装(默认安装1.7.X版本的JQ) npm/cnpm install jQuery 如果想安装更高版本的JQ那么可以选择在package.json文件下面这个位置添加代码断&#xff08;当前图片安装的是2.2.3版本&#xff0c;如果想安装更高或者其他可以更改版本号&…

Unity——用UnityEditor拷贝FBX中的AnimationClip

最近有个新需求&#xff0c;要用代码添加动画的事件&#xff0c;但是Unity不能直接修改FBX中的AnimationClip 在Animation窗口中可以看到&#xff0c;AnimationClip是Read-Only状态&#xff0c;用代码修改这个AnimationClip也是不会生效的&#xff0c;包括用代码添加事件 解决方…

mvc如何嵌套第三方页面_长文观点丨为什么我不再使用MVC框架?

原创&#xff1a; 张卫滨 译 Jean-Jacques Dubray是一名资深工程师&#xff0c;他最近引入了一个新的模式&#xff1a;状态-行为-模(State-Action-Model&#xff0c;SAM)。SAM是一个函数式反应型的编程模式&#xff0c;它致力于简化数据Model和View之间的交互。它究竟有何优点值…

JSON和XML的区别

转载于:https://www.cnblogs.com/mr-wuxiansheng/p/6974239.html

屏幕适配

rem是什么&#xff1f; rem&#xff08;font size of the root element&#xff09;是指相对于根元素的字体大小的单位。简单的说它就是一个相对单位。看到rem大家一定会想起em单位&#xff0c;em&#xff08;font size of the element&#xff09;是指相对于父元素的字体大小…

【存储过程】MySQL存储过程/存储过程与自定义函数的区别

---------------------------存储过程-------------------- 语法: 创建存储过程: CREATE [definer {user|current_user}] PROCEDURE sp_name ([ proc_parameter [,proc_parameter ...]]) [ characteristics..] routime_body 其中: proc_parameter : [IN|OUT|INOUT] parameter_…

Java死锁故障排除和解决

JavaOne年度会议的一大优点是&#xff0c;主题专家介绍了几个技术和故障排除实验室。 其中的一个实验室今年特别吸引了我的注意力&#xff1a;“ HOL6500-查找和解决Java死锁 ”&#xff0c;由Java冠军Heinz Kabutz提出 。 这是我在该主题上看到的最好的演示之一。 我建议您自己…

3. HTML中的容器标签

什么是容器标签&#xff1f;在HTML开发中我们常常会使用一类标签作为容器放置一些内容&#xff0c;我们把这类标签称之为容器标签&#xff0c;可以作为容器标签的包括列表标签、表格标签、框架标签、布局标签&#xff0c;在这里我们就来总结下这些内容。 列表标签 1 <!-- 无…

GitHub上Java的Bloom Bloom实现

布隆过滤器是集数据结构的一种 。 对于那些不了解的对象&#xff0c;“设置数据结构”仅包含一个主要方法。 它仅用于确定特定元素是否包含在一组元素中。 大多数数据结构&#xff08;例如Hash Map &#xff0c; Linked List或Array &#xff09;都可以相当轻松地创建此函数。 …

ni软件管理器_NI 技术支持丨我的 NI 硬件设备不能被识别,怎么办?Windows

这篇指南可以帮助您解决在您的 Windows 系统上无法识别您的 NI 硬件有关的问题。症状包括以下几种情况&#xff1a;连接至 USB 端口时&#xff0c;硬件上的 LED 灯不亮/不闪烁。连接至 USB 后已连接设备的 LED 灯持续闪烁。仅限音频接口&#xff1a;该设备在音频应用程序或 Win…

在Java应用程序中使用密码学

这篇文章描述了如何使用Java密码体系结构 &#xff08;JCA&#xff09;&#xff0c;该体系结构使您可以在应用程序中使用密码服务。 Java密码体系结构服务 JCA提供了许多加密服务&#xff0c;例如消息摘要和签名 。 这些服务可以通过特定于服务的API来访问&#xff0c;例如Me…

CSS学习笔记-04 a标签-导航练习

个人练习&#xff0c;各位大神勿笑 。。 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><meta http-equiv&qu…

深度学习loss值变为0_利用TensorFlow2.0为胆固醇、血脂、血压数据构建时序深度学习模型(python源代码)...

背景数据描述胆固醇、高血脂、高血压是压在广大中年男性头上的三座大山&#xff0c;如何有效的监控他们&#xff0c;做到早发现、早预防、早治疗尤为关键&#xff0c;趁着这个假期我就利用TF2.0构建了一套时序预测模型&#xff0c;一来是可以帮我预发疾病&#xff0c;二来也可以…

在Spring MVC Web应用程序中使用reCaptcha

CAPTCHA是一种程序&#xff0c;可以生成人类可以通过的测试并对其进行评分&#xff0c;而计算机程序“ 不能 ”通过。 所采取的策略之一是向用户显示具有扭曲文本的图像&#xff0c;并且用户应在输入区域中书写文本。 如果显示的文字与用户输入的文字相同&#xff0c;则我们可以…

课时109.外边距合并现象(掌握)

我们先写一个案例&#xff0c;通过案例来了解 它们之间的水平距离就是两个间距的和 我们看完水平再来看垂直方向 在默认布局的垂直方向上&#xff0c;默认情况下外边距是不会叠加的&#xff0c;会出现合并现象&#xff0c;谁的外边距比较大就听谁的 本文转载于:猿2048➜https:…