场景:模拟银行账户转账
创建一个模拟银行账户类,支持多线程环境下并发转账操作。确保转账过程中账户余额不会出现负数,并且转账金额正确。
示例代码
银行账户类
有1个属性,账户余额
有3个方法,存款,转账,查账户余额。
public class BankAccount {
// 账户余额
private double balance = 0;
private String accountName;
public BankAccount(){
}
public BankAccount(String accountName){
this.accountName = accountName;
}
public BankAccount(String accountName, double balance){
this.accountName = accountName;
this.balance = balance;
}
/**
* 存款
* @param amount 存款金额
*/
public synchronized void deposit(double amount){
if(amount > 0){
balance += amount;
System.out.printf("账户:%s, 存入金额:%.2f,账户余额:%.2f", accountName, amount, balance);
System.out.println();
}
}
/**
* 取款
* @param amount 取款金额
* @return 如果有足够的资金并且取款成功,则返回true;否则返回false;
*/
public synchronized boolean withdraw(double amount){
if(amount > 0 && balance >= amount){
balance -= amount;
System.out.printf("账户:%s, 取出金额:%.2f,账户余额:%.2f", accountName, amount, balance);
System.out.println();
return true;
}else{
System.out.printf("账户:%s, 账户余额不足", accountName);
System.out.println();
return false;
}
}
/**
* 查询账户余额
* @return 账户余额
*/
public synchronized double getBalance(){
return this.balance;
}
}
转账demo
public class BankTransferDemo {
public static void transfer(BankAccount from, BankAccount to, double amount) throws InterruptedException {
// 模拟网络延迟
TimeUnit.MICROSECONDS.sleep((long) (Math.random() * 100));
// 取款失败则直接结束
if(!from.withdraw(amount)){
return;
}
to.deposit(amount);
}
public static void main(String[] args) {
demo2();
}
/**
* 从不同账户往同一账户存钱
*/
public static void demo2(){
BankAccount account1 = new BankAccount("account1", 1000);
BankAccount account2 = new BankAccount("account2", 1000);
BankAccount account3 = new BankAccount("account3", 1000);
BankAccount account4 = new BankAccount("account4", 1000);
BankAccount account5 = new BankAccount("account5", 1000);
BankAccount account6 = new BankAccount("account6", 1000);
BankAccount account = new BankAccount("account", 0);
Thread thread1 = new Thread(() -> {
try {
transfer(account1, account, 200);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
Thread thread2 = new Thread(() -> {
try {
transfer(account2, account, 300);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
Thread thread3 = new Thread(() -> {
try {
transfer(account3, account, 400);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
Thread thread4 = new Thread(() -> {
try {
transfer(account4, account, 500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
Thread thread5 = new Thread(() -> {
try {
transfer(account5, account, 600);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
Thread thread6 = new Thread(() -> {
try {
transfer(account6, account, 1200);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
thread1.start();
thread2.start();
thread3.start();
thread4.start();
thread5.start();
thread6.start();
try {
thread1.join();
thread2.join();
thread3.join();
thread4.join();
thread5.join();
thread6.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
// 输出账户余额
System.out.printf("Final Balances: Account1: %.2f", account.getBalance());
}
/**
* 从同一账户多次取钱,存入同一账户
*/
public static void demo1(){
BankAccount account1 = new BankAccount("account1");
BankAccount account2 = new BankAccount("account2");
// 初始存款
account1.deposit(1000);
// 创建线程执行转载操作
Thread thread1 = new Thread(() -> {
try {
transfer(account1, account2, 200);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
// 创建线程执行转载操作
Thread thread2 = new Thread(() -> {
try {
transfer(account1, account2, 100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
thread1.start();
thread2.start();
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
// 输出账户余额
System.out.printf("Final Balances: Account1: %.2f, Account2: %.2f%n", account1.getBalance(), account2.getBalance());
}
demo1的结果
demo2的结果
总结
其实模拟的是多个线程无序地访问和修改同一个共享资源。