死锁之加锁顺序

package thread.test;

import java.math.BigDecimal;
import java.util.Currency;

public abstract  class Amount implements Comparable<Amount>{
	public abstract BigDecimal getBalance();
	public abstract void setBalance(BigDecimal balance);
	public abstract Currency getCurrency();
	
	@Override
	public int compareTo(Amount o) {
		if(o==null){
			throw new NullPointerException("null arg.");
		}
		
		if(this.getBalance()==null||o.getBalance()==null){
			throw new NullPointerException("null arg.");
		}
		
		return this.getBalance().compareTo(o.getBalance());
	}
}
package thread.test;

import java.math.BigDecimal;
import java.util.Currency;
import java.util.Locale;

public class DollarAmount extends Amount{
	private BigDecimal balance;
	private Currency currency = Currency.getInstance(Locale.US);
	
	public DollarAmount(BigDecimal balance){
		this.balance = balance;
	}
	
	public BigDecimal getBalance() {
		return balance;
	}
 
	public void setAmount(BigDecimal amount) {
		this.balance = amount;
	}
 
	public Currency getCurrency() {
		return currency;
	}
 
	public void setBalance(BigDecimal balance) {
		this.balance = balance;
	}

	 
}
package thread.test;

import java.math.BigDecimal;

public class Account {
	private String id;
	private Amount balance;
	
	public Account(Amount amount,String id){
		this.balance = amount;
		this.id = id;
	}
	
	public Amount getBalance() {
		return balance;
	}
 
	public void setBalance(Amount balance) {
		this.balance = balance;
	}
 
	public void debit(Amount amount){
		if(this.balance==null||amount==null||amount.getBalance()==null){
			return;
		}
		
		System.out.println(id+" 支出金额"+amount.getBalance());
		
		//修正账户余额:本账户减去借方金额
		BigDecimal current = this.balance.getBalance();
		BigDecimal now = current.subtract(amount.getBalance());
		this.balance.setBalance(now);
	}
	
	public void credit(Amount amount){
		if(this.balance==null||amount==null||amount.getBalance()==null){
			return;
		}
		
		System.out.println(id+" 收入金额"+amount.getBalance());
		
		//修正账户余额:本账户加贷方金额
		BigDecimal current = this.balance.getBalance();
		BigDecimal now = current.add(amount.getBalance());
		this.balance.setBalance(now);
	}
 
	public String getId() {
		return id;
	}
 
	public void setId(String id) {
		this.id = id;
	}

}
package thread.test;

public class AccountHelper {
	//加时赛锁
		private final Object tieLock = new Object();

	public void transferMoney(final Account fromAcct,
			final Account toAcct,
			final Amount amount){
		//参数校验
		if(fromAcct==null||toAcct==null||amount==null){
			throw new IllegalArgumentException("null arg.");
		}
		
		//余额校验
		if(fromAcct.getBalance().compareTo(amount)<0){
			throw new IllegalArgumentException(fromAcct.getId()+"账户余额不足");
		}
		//根据对象的hash值随机设置加锁顺序
				int fromHash = System.identityHashCode(fromAcct);
				int toHash = System.identityHashCode(toAcct);
		
		if(fromHash<toHash){
			synchronized (fromAcct) {
				synchronized (toAcct) {
					this.transfer(fromAcct, toAcct, amount);
				}
			}
		}else if(fromHash>toHash){
			synchronized (toAcct) {
				synchronized (fromAcct) {
					this.transfer(fromAcct, toAcct, amount);
				}
			}
		}else{
			//碰巧相对时,先获取加时赛锁
			synchronized (tieLock) {
				synchronized (fromAcct) {
					synchronized (toAcct) {
						this.transfer(fromAcct, toAcct, amount);
					}
				}
			}
		}

	}
	
	//transfer对两个账户的操作必须是原子的完成
	private void transfer(final Account fromAcct,
			final Account toAcct,
			final Amount amount){
		System.out.println("Thread "+Thread.currentThread().getName()+" do transfer.");
		fromAcct.debit(amount);
		toAcct.credit(amount);
	}


}
package thread.test;

import java.math.BigDecimal;

public class MainTest {
	public static void main(String[] args) {
		Amount amFromAcc = new DollarAmount(new BigDecimal(2000));
		Amount amToAcc = new DollarAmount(new BigDecimal(1000));
		final AccountHelper h = new AccountHelper();
		
		final Account fromAcc = new Account(amFromAcc,"zhang_3");
		final Account toAcc = new Account(amToAcc,"wang_5");
		final Amount amToTran = new DollarAmount(new BigDecimal(1));
		Thread t1 = new Thread(new Runnable(){
			@Override
			public void run() {
				h.transferMoney(fromAcc, toAcc, amToTran);
			}
			
		});
		Thread t4 = new Thread(new Runnable(){
			@Override
			public void run() {
				h.transferMoney(fromAcc, toAcc, amToTran);
			}
		});
		Thread t2 = new Thread(new Runnable(){
			@Override
			public void run() {
				h.transferMoney(toAcc, fromAcc, amToTran);
			}
		});
		Thread t3 = new Thread(new Runnable(){
			@Override
			public void run() {
				h.transferMoney(toAcc, fromAcc, amToTran);
			}
		});
		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值