Java通过锁的顺序避免死锁

内容:通过获取锁的顺序来避免死锁。例如:银行账户转账问题,两个用户转账的话,如果采用一般的synchronized嵌套的话,容易造成死锁,现在我们通过类似哲学家问题的解决方案一样:先获取同一个锁,才有资格获取下一个。而判断是通过System.identityHashCode()来生成类的hashcode()的返回值作为唯一标识,相同的话,我们再加一把锁。

class Account {
	private int money;
	
	public Account(int money) {
		this.money = money;
	}
	
	public void debit(int amount) {
		System.out.println("after debit " + amount + " " + this.money + " -> " + (this.money-amount));
		this.money -= amount;
	}
	
	public void credit(int amount) {
		System.out.println("after credit " + amount + " " + this.money + " -> " + (this.money+amount));
		this.money += amount;
	}
	
	public int get() {
		return this.money;
	}
}

public class OrderLock {
	private static final Object tieLock = new Object();
	
	public void transferMoney(final Account fromAcct, final Account toAcct, final int amount) 
			throws InsufficientResourcesException {
		class Helper {
			public void transfer() throws InsufficientResourcesException {
				if (fromAcct.get() < amount) 
					throw new InsufficientResourcesException();
				else {
					fromAcct.debit(amount);
					toAcct.credit(amount);
				}
			}
		}
		
		int fromHash = System.identityHashCode(fromAcct);
		int toHash = System.identityHashCode(toAcct);
		
		if (fromHash < toHash) {
			synchronized (fromAcct) {
				synchronized (toAcct) {
					new Helper().transfer();
				}
			}
		} else if (fromHash > toHash) {
			synchronized (toAcct) {
				synchronized (fromAcct) {
					new Helper().transfer();
				}
				
			}
		} else {
			synchronized (tieLock) {
				synchronized (fromAcct) {
					synchronized (toAcct) {
						new Helper().transfer();
					}
				}
			}
		}
	}
	
	class MyThread implements Runnable {
		private Account fromAcct;
		private Account toAcct;
		private int amount;
		
		public MyThread(Account fromAcct, Account toAcct, int amount) {
			this.fromAcct = fromAcct;
			this.toAcct = toAcct;
			this.amount = amount;
		}


		@Override
		public void run() {
			try {
				transferMoney(this.fromAcct, this.toAcct, this.amount);
			} catch (InsufficientResourcesException e) {
				System.out.println("操作失败");
			}
		}
		
	}
	
	public static void main(String[] args) {
		Account fromAcct = new Account(100);
		Account toAcct = new Account(230);
		OrderLock orderLock = new OrderLock();
		ExecutorService threadPool = Executors.newCachedThreadPool();
		for (int i = 0; i < 5; i++) {
			if ((i & 1) == 0)
				threadPool.execute(orderLock.new MyThread(fromAcct, toAcct, 10));
			else threadPool.execute(orderLock.new MyThread(toAcct, fromAcct, 10));
		}
	}
}


郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。