Java多线程 死锁转账案例 - 日理万妓 2022-12-05 01:37 204阅读 0赞 ### 文章目录 ### * * * 两个转账的死锁demo ### 两个转账的死锁demo ### 需要两把锁: 转账时, 锁住自己的账户, 同时只能有一个线程去执行转账. 获取两把锁成功, 且余额大于0 , 则扣除转出人的钱, 增加收款人的钱. 并且是原子操作. 出现死锁的情况: 对方给我转钱 ,我也给对方转钱, 那么双方都持有自己的锁, 并且需要对方的锁, 这就造成了死锁. 如下的代码演示了转账死锁的发生. 在run方法中, 根据不同线程的flag 执行不同的转账方法,分别给a和b相互的转账. transferMoney方法就是转账的方法. 在转账的方法中, 分别要获取转账方和收款方的两把锁, 才能进行转账的操作. package com.thread.deadlock; /** * 类名称:TransferMoney * 类描述: 转账时遇到死锁的代码演示 * * @author: https://javaweixin6.blog.csdn.net/ * 创建时间:2020/9/8 19:24 * Version 1.0 */ public class TransferMoney implements Runnable { //根据不同的flag, 给不同的人转账 int flag = 1 ; static Account a = new Account(500); static Account b = new Account(500); public static void main(String[] args) throws InterruptedException { TransferMoney r1 = new TransferMoney(); TransferMoney r2 = new TransferMoney(); r1.flag = 1; r2.flag = 0; Thread thread1 = new Thread(r1); Thread thread2 = new Thread(r2); thread1.start(); thread2.start(); //主线程等待子线程执行完毕 thread1.join(); thread2.join(); System.out.println("a的余额 " +a.balance); System.out.println("b的余额 " +b.balance); } @Override public void run() { //flag 是1 则 a 给b钱 if (flag == 1) { transferMoney(a, b, 200); } //flag 是0 则b 给a钱 if (flag == 0) { transferMoney(b, a, 200); } } /** * 转账的方法 * @param from 转账方 * @param to 收账方 * @param amount 金额 */ public static void transferMoney(Account from, Account to, int amount) { synchronized (from) { synchronized (to) { //转账前判断余额是否充足 if (from.balance - amount < 0) { System.out.println("余额不足, 转账失败"+Thread.currentThread().getName()); return; } //余额充足,则进行转账操作. 转账方扣钱, 收款方收钱 from.balance -=amount; to.balance +=amount; System.out.println("成功转账" +amount +"元 "+Thread.currentThread().getName()); } } } //账户的静态内部类 static class Account { //余额 int balance; public Account(int balance) { this.balance = balance; } } } 运行程序, 此时成功的执行的转账的操作. 线程名为0和1 的线程, 分别去转账的方法中执行的转账,由于相互给对方转账200. 因此余额不变. ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMzMjI5NjY5_size_16_color_FFFFFF_t_70_pic_center][] 修改如下: package com.thread.deadlock; /** * 类名称:TransferMoney * 类描述: 转账时遇到死锁的代码演示 * * @author: https://javaweixin6.blog.csdn.net/ * 创建时间:2020/9/8 19:24 * Version 1.0 */ public class TransferMoney implements Runnable { //根据不同的flag, 给不同的人转账 int flag = 1 ; static Account a = new Account(500); static Account b = new Account(500); public static void main(String[] args) throws InterruptedException { TransferMoney r1 = new TransferMoney(); TransferMoney r2 = new TransferMoney(); r1.flag = 1; r2.flag = 0; Thread thread1 = new Thread(r1); Thread thread2 = new Thread(r2); thread1.start(); thread2.start(); //主线程等待子线程执行完毕 thread1.join(); thread2.join(); System.out.println("a的余额 " +a.balance); System.out.println("b的余额 " +b.balance); } @Override public void run() { //flag 是1 则 a 给b钱 if (flag == 1) { transferMoney(a, b, 200); } //flag 是0 则b 给a钱 if (flag == 0) { transferMoney(b, a, 200); } } /** * 转账的方法 * @param from 转账方 * @param to 收账方 * @param amount 金额 */ public static void transferMoney(Account from, Account to, int amount) { synchronized (from) { try { Thread.sleep(20); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (to) { //转账前判断余额是否充足 if (from.balance - amount < 0) { System.out.println("余额不足, 转账失败"+Thread.currentThread().getName()); return; } //余额充足,则进行转账操作. 转账方扣钱, 收款方收钱 from.balance -=amount; to.balance +=amount; System.out.println("成功转账" +amount +"元 "+Thread.currentThread().getName()); } } } //账户的静态内部类 static class Account { //余额 int balance; public Account(int balance) { this.balance = balance; } } } 修改了获取第二把锁之前, 给当前线程休眠20ms . ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMzMjI5NjY5_size_16_color_FFFFFF_t_70_pic_center 1][] 此时再运行程序, 可以看到控制台什么都没有打印, 红色的按钮一直亮着, 说明进入了死锁的状态. 两个线程都只是执行到上图中的第67行代码就执行不下去了. ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMzMjI5NjY5_size_16_color_FFFFFF_t_70_pic_center 2][] 死锁的原因分析. 第一个线程进入如下的方法后, 获得了from这把锁, 接着sleep,进入timed\_waiting状态, 并且由于是sleep, 并不会释放from这把锁. 此时CPU调度执行第二个线程, 第二个线程的from为第一个线程的to锁, 第二个线程获得了to锁后, 也进入timed\_waiting状态, 持有to锁不会释放. 接着CPU切回第一个线程,想要去获取to锁, 但是获取不到,因为被第二个线程所持有着. 第二个线程持有to锁, 想要去获得from锁也获取不到, 那么就进入了死锁的状态. ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMzMjI5NjY5_size_16_color_FFFFFF_t_70_pic_center 3][] 死锁形成的原因就是如下的方法中, 锁获得的循序是相反的, ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMzMjI5NjY5_size_16_color_FFFFFF_t_70_pic_center 4][] 补充: 上面demo代码给两个账户类, 创建的都是static对象, 而static对象在整个Java虚拟机中只有一个实例, 所以不同线程获取锁的时候, 始终只有一个线程获得到这把锁. 此种情况适用于单体的项目. 而分布式的情况获得锁是不一样的,需要另外的方法进行处理. [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMzMjI5NjY5_size_16_color_FFFFFF_t_70_pic_center]: /images/20221123/321eb4de42da4e848331d34dba687af5.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMzMjI5NjY5_size_16_color_FFFFFF_t_70_pic_center 1]: /images/20221123/ced7c55623334227a4faca46e9a2f1b6.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMzMjI5NjY5_size_16_color_FFFFFF_t_70_pic_center 2]: /images/20221123/9384e6d5e2554cccae2e99d4a54fc96e.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMzMjI5NjY5_size_16_color_FFFFFF_t_70_pic_center 3]: /images/20221123/346c615565714439af04fa118b8b73d8.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMzMjI5NjY5_size_16_color_FFFFFF_t_70_pic_center 4]: /images/20221123/c59a7766ca3c48b3b019c54e9f7d58fa.png
相关 多线程并发:Java线程同步死锁案例 在Java编程中,多线程并发和线程同步是两个重要的概念。下面我们将通过一个死锁的例子来深入理解。 首先,了解什么是死锁: - 死锁:两个或更多的线程因争夺资源而造成的一种互相 落日映苍穹つ/ 2024年09月18日 01:03/ 0 赞/ 14 阅读
相关 Java多线程编程:同步锁和死锁案例 Java多线程编程中,同步锁主要有两种方式:synchronized关键字和Lock接口。 1. `synchronized`关键字: ```java // 假设有一个共享 迷南。/ 2024年09月17日 14:57/ 0 赞/ 14 阅读
相关 Java多线程:死锁案例解析 死锁是多线程编程中的一种严重问题,当两个或更多的线程在执行过程中因争夺资源而造成的一种互相等待的现象称为死锁。 下面是一个简单的死锁案例,使用Java实现: ```java 爱被打了一巴掌/ 2024年09月10日 16:30/ 0 赞/ 23 阅读
相关 Java多线程问题:死锁案例 死锁是多线程编程中的一种严重问题,当两个或更多的线程因争夺资源而造成的一种互相等待的现象时,就会发生死锁。 下面是一个经典的死锁案例: ```java // 线程1,持有资 柔光的暖阳◎/ 2024年09月05日 19:18/ 0 赞/ 20 阅读
相关 JAVA多线程—线程死锁 程死锁: 创建两个字符串a和b,再创建两个线程A和B,让每个线程都用synchronized锁住字符串(A先锁a,再去锁b;B先锁b,再锁a),如果A锁住a,B锁住b,... 妖狐艹你老母/ 2024年04月17日 22:29/ 0 赞/ 51 阅读
相关 Java多线程 多个人转账发生死锁 文章目录 多个人转账发生死锁 多个人转账发生死锁 人数多的时候, 依然会发生死锁, 遵循墨菲定律. 虽然人多的时候发生死锁的几率不高, 但是 朴灿烈づ我的快乐病毒、/ 2022年12月05日 04:54/ 0 赞/ 97 阅读
相关 Java多线程 死锁转账案例 文章目录 两个转账的死锁demo 两个转账的死锁demo 需要两把锁: 转账时, 锁住自己的账户, 同时只能有一个线程去执行转账. 获取两把 - 日理万妓/ 2022年12月05日 01:37/ 0 赞/ 205 阅读
相关 java多线程死锁死锁案例 / 两个线程先分别持有两把锁,然后再去请求对方的锁,导致死锁 / public class DeadLock extends Thread 蔚落/ 2022年03月14日 11:18/ 0 赞/ 362 阅读
相关 Java多线程死锁案例 产生死锁的原因 就是,两个线程互相等待着对象释放锁,一直这样僵持下去,所以导致了死锁的产生,下面这个代码就会产生一个死锁: package com.exampl 落日映苍穹つ/ 2021年12月20日 04:09/ 0 赞/ 310 阅读
还没有评论,来说两句吧...