多线程银行转账死锁优化

多线程银行转账死锁问题

在转账操作中,一致性必须要保证的,转账的前后,各个账户的金额必须符合算术一致性,如果在转账方法上直接加锁,那相当于整个转账过程都是单线程的,并发和性能不高,如果针对账户加锁,会存在A->B,B->A之间死锁问题**

- 账户信息

public class Account {
	private String id;
	private String name;// 账号
	private  int balance;// 资金总额

	public Account(String id,String name, int balance) {
		this.id = id;
		this.name = name;
		this.balance = balance;
	}
	public String getName() {
		return name;
	}
	public int getBalance() {
		return balance;
	}
	public String getId() {
		return id;
	}
	public void debit(int amount) {// 更新转出方余额
		this.balance -= amount;
	}
	public void credbit(int amount) {// 更新转入方余额
		this.balance += amount;
	}
  • 转账实现,根据对账户进行排序加锁
public interface Transfer {
	public void transfer(Account from, Account to, int amount);
}

public class TransferImpl implements Transfer {

	public void transfer(Account fromAccount, Account toAccount, int amount) {

		int fromHashCode = fromAccount.getId().hashCode();
		int toHashCode = toAccount.getId().hashCode();

		Account left = fromAccount;
		Account right = toAccount;

		// 按从小到大排序
		if (fromHashCode > toHashCode) {
			left = toAccount;
			right = fromAccount;
		}

		synchronized (left) {
			// 获取right的锁
			synchronized (right) {
				// 两个锁都获取到执行操作
				if (fromAccount.getBalance() <= amount) {
					System.out.println(Thread.currentThread().getName()+"->"+fromAccount.getName() + "账户余额不足,无法进行转账"+" 余额:"+fromAccount.getBalance()+"<"+amount);
					return;
				}
				fromAccount.debit(amount);
				System.err.println(Thread.currentThread().getName()+"->"+fromAccount.getName() + "**转出**" + amount+"**剩余**" + fromAccount.getBalance());
				toAccount.credbit(amount);
				System.out.println(Thread.currentThread().getName()+"->"+toAccount.getName() + "--被【"+fromAccount.getName()+"】转入--" + amount+"--剩余--" + toAccount.getBalance());
			}
		}

	}

	public static void main(String[] args) {

		List<Account> allAccount = new ArrayList<Account>();

		allAccount.add(new Account("1","张三", 100));
		allAccount.add(new Account("2","李四", 100));
		allAccount.add(new Account("3","小梅", 100));
		allAccount.add(new Account("4","小明", 100));

		for (int i = 0; i < 10; i++) {
			int findex = ThreadLocalRandom.current().nextInt(4);
			int toindex = ThreadLocalRandom.current().nextInt(4);

			int amount = ThreadLocalRandom.current().nextInt(50,80);
			if (findex != toindex) {
				Runnable r = new TransferThread(allAccount.get(findex), allAccount.get(toindex), amount,allAccount);
				new Thread(r).start();
			}
		}
	}

	public static class TransferThread implements Runnable {

		private Account fromAccount;
		private Account toAccount;
		private int amount;
		private List<Account> allAccount;

		public TransferThread(Account fromAccount, Account toAccount, int amount,List<Account> allAccount) {
			this.fromAccount = fromAccount;
			this.toAccount = toAccount;
			this.amount = amount;
			this.allAccount = allAccount;
		}

		public void run() {
			new TransferImpl().transfer(fromAccount, toAccount, amount);
			
			int total = 0;
			
			for(Account account:allAccount) {
				total = total + account.getBalance();
			}
			System.err.println(Thread.currentThread().getName()+"-> total:" + total);
		}
	}

}

- 执行结果
Thread-0->李四转出58剩余42
Thread-0->张三–被【李四】转入–58–剩余–158
Thread-3->李四账户余额不足,无法进行转账 余额:42<66
Thread-2->李四–被【小明】转入–74–剩余–116
Thread-1->李四–被【张三】转入–67–剩余–183
Thread-2->小明转出74剩余26
Thread-1->张三转出67剩余91
Thread-3-> total:400
Thread-0-> total:400
Thread-2-> total:400
Thread-1-> total:400

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值