Java多线程并发问题:模拟银行账户存款取款
Java多线程并发问题:模拟银行账户存款取款
以下Java代码模拟了银行账户的存款和取款操作,并演示了多线程环境下可能出现的并发问题:
public class BankAccount {
private int balance;
public BankAccount(int initialBalance) {
balance = initialBalance;
}
public synchronized void deposit(int amount) {
balance += amount;
}
public synchronized void withdraw(int amount) {
balance -= amount;
}
public synchronized int getBalance() {
return balance;
}
}
public class Accountant implements Runnable {
private BankAccount account;
public Accountant(BankAccount account) {
this.account = account;
}
public void run() {
for (int i = 0; i < 10000; i++) {
account.deposit(1);
}
}
}
public class Cashier implements Runnable {
private BankAccount account;
public Cashier(BankAccount account) {
this.account = account;
}
public void run() {
for (int i = 0; i < 10000; i++) {
account.withdraw(1);
}
}
}
public class Bank {
public static void main(String[] args) {
BankAccount account = new BankAccount(10000);
Thread t1 = new Thread(new Accountant(account));
Thread t2 = new Thread(new Cashier(account));
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println('Final balance: ' + account.getBalance());
}
}
问题分析
代码中,Accountant线程模拟存款操作,Cashier线程模拟取款操作。由于两个线程都并发的对同一个BankAccount对象进行操作,而且deposit和withdraw方法没有进行同步处理,因此会出现数据不一致的问题。
例如,假设初始余额为10000,Accountant线程执行deposit(1)操作时,首先读取当前余额为10000,然后将其加1得到10001,但在写入新余额之前,Cashier线程也执行了withdraw(1)操作,同样读取到余额为10000,将其减1得到9999,并写入新余额。最终导致Accountant线程的存款操作被覆盖,余额变成9999,而不是预期的10001。
解决方案
为了解决这个问题,我们需要对deposit和withdraw方法进行同步控制,确保同一时间只有一个线程可以修改账户余额。在本例中,我们使用synchronized关键字来实现同步控制。
通过将deposit和withdraw方法声明为synchronized,我们可以确保在任何时刻只有一个线程可以执行这些方法。当一个线程正在执行deposit或withdraw方法时,其他线程将被阻塞,直到该线程完成操作并释放锁。
总结
多线程并发访问共享资源是Java编程中常见的问题,如果不进行同步控制,就会导致数据不一致等问题。synchronized关键字是Java提供的一种简单有效的同步机制,可以帮助我们解决这类问题。
原文地址: https://www.cveoy.top/t/topic/jmi8 著作权归作者所有。请勿转载和采集!