今日项目之线程同步操作项目
目录
要求
这该如何是好
代码实现
项目结构
代码
BankAccount.java
WithdrawTask.java
Main.java
执行结果
关键点
关键点解释
要求
使用线程同步实现两个用户同时安全操作一个银行账户
张三准备取款
张三完成取款
张三的妻子准备取款
张三的妻子完成取款
张三准备取款
张三完成取款
张三的妻子准备取款
张三的妻子完成取款
张三准备取款
张三完成取款
余额不足以支付张三的妻子的取款,余额为C
余额不足以支付张三的取款,余额为0
余额不足以支付张三的妻子的取款,余额为0
余额不足以支付张三的取款,余额为0
余额不足以支付张三的妻子的取款,余额为0
这该如何是好
思路 | 说明 |
---|---|
线程同步 | 使用synchronized关键字确保账户操作的原子性 |
竞态条件 | 解决多线程同时访问共享资源导致的数据不一致问题 |
线程安全 | 通过同步方法保证账户状态的一致性 |
阻塞机制 | synchronized实现的隐式锁机制 |
共享资源 | BankAccount作为多个线程共享的临界资源 |
线程通信 | 通过控制台输出展示线程执行顺序 |
代码实现
项目结构
BankAccountSync/ ├── src/ ├── BankAccount.java # 银行账户类 ├── WithdrawTask.java # 取款任务类 └── Main.java # 主程序
代码
BankAccount.java
public class BankAccount {private int balance;private final String accountName;public BankAccount(String accountName, int initialBalance) {this.accountName = accountName;this.balance = initialBalance;}// 同步取款方法public synchronized void withdraw(String userName, int amount) {System.out.println(userName + "准备取款");try {// 模拟实际业务处理延迟Thread.sleep(100);} catch (InterruptedException e) {Thread.currentThread().interrupt();}if (balance >= amount) {balance -= amount;System.out.println(userName + "完成取款");} else {System.out.println("余额不足以支付" + userName + "的取款,余额为" + balance);}}public int getBalance() {return balance;}
}
WithdrawTask.java
public class WithdrawTask implements Runnable {private final BankAccount account;private final String userName;private final int amount;public WithdrawTask(BankAccount account, String userName, int amount) {this.account = account;this.userName = userName;this.amount = amount;}@Overridepublic void run() {account.withdraw(userName, amount);}
}
Main.java
public class Main {public static void main(String[] args) {// 创建初始余额为3000的账户BankAccount account = new BankAccount("家庭账户", 3000);// 创建取款任务线程Thread zhangsanThread1 = new Thread(new WithdrawTask(account, "张三", 1000));Thread wifeThread1 = new Thread(new WithdrawTask(account, "张三的妻子", 1000));Thread zhangsanThread2 = new Thread(new WithdrawTask(account, "张三", 1000));Thread wifeThread2 = new Thread(new WithdrawTask(account, "张三的妻子", 1000));Thread zhangsanThread3 = new Thread(new WithdrawTask(account, "张三", 1000));Thread wifeThread3 = new Thread(new WithdrawTask(account, "张三的妻子", 1000));// 按题目要求的顺序启动线程zhangsanThread1.start();try { Thread.sleep(50); } catch (InterruptedException e) {} // 确保启动顺序wifeThread1.start();try { Thread.sleep(50); } catch (InterruptedException e) {}zhangsanThread2.start();try { Thread.sleep(50); } catch (InterruptedException e) {}wifeThread2.start();try { Thread.sleep(50); } catch (InterruptedException e) {}zhangsanThread3.start();try { Thread.sleep(50); } catch (InterruptedException e) {}wifeThread3.start();// 等待所有线程完成try {zhangsanThread1.join();wifeThread1.join();zhangsanThread2.join();wifeThread2.join();zhangsanThread3.join();wifeThread3.join();} catch (InterruptedException e) {Thread.currentThread().interrupt();}}
}
执行结果
关键点
关键点解释
-
线程同步机制:
-
使用
synchronized
修饰withdraw
方法,确保同一时间只有一个线程能执行取款操作 -
防止多个线程同时修改余额导致的数据不一致
-
-
余额控制逻辑:
-
每次取款前检查余额是否充足
-
余额不足时输出警告信息而不修改余额
-
初始余额3000元,每次取款1000元
-
-
线程启动顺序:
-
使用
Thread.sleep(50)
确保线程按题目要求的顺序启动 -
实际业务中通常不需要控制启动顺序,此处仅为满足题目输出要求
-
-
余额变化过程:
-
前三次取款成功(3000→2000→1000→0)
-
后续取款因余额不足失败
-