旺财和小强的三生三世
作者:CQITer小编 时间:2019-01-15 21:37
旺财和小强是线程池的两个线程, 他们经常做的工作就是对一个数加加减减,用人类的话来说就是存款,取款。
public class Account{
private int balance;
public synchronized void deposit(int amt){
balance += amt;
}
public synchronized void withdraw(int amt){
if(balance >= amt){
balance -= amt;
}
throw new RuntimeException("insufficent blance");
}
}
(友情提示,可左右滑动,下同)
每次进行存款,取款操作的时候,他们两个都需要获得一把锁,这样就能保证同一时刻只有一个人在修改,不会出乱子。
这一天,他们俩又遇到了一个叫做转账的操作:
public void transfer(Account from,Account to, int amt){
synchronized(from){
synchronized(to){
from.withdraw(amt);
to.deposit(amt);
}
}
}
旺财说:“这个程序员不错,考虑得挺周全。转账的时候把两个账户都锁住了,安全!”
小强说:“没错,执行吧。”
旺财这个线程从A向B转账 , 与此同时,小强从B向A转账
令旺财和小强没有想到的是,居然出现了死锁。

类似的事件发生不少, 线程池的线程用光了,Tomcat被迫重启,这个世界毁灭了。
第二世
新生代的旺财和小强从线程池中出来, Tomcat老大给他们讲了上一代旺财和小强的故事, 对他们谆谆教导:“做转账操作的时候一定要小心,别死锁了!”
旺财和小强有点儿愤愤不平:“这我们俩也控制不了啊,这要看程序员写的代码,以及操作系统中的线程调度啊!”
不满归不满,他俩还是有点小期待,想看看可怕的转账代码到底怎么样。
没过多久, 他俩就如愿了:
public static final Object lock = new Object();
public void transfer(Account from,Account to, int amt){
int fromHash = System.identityHashCode(from);
int toHash = System.identityHashCode(to);
if(fromHash > toHash){
synchronized(from){
synchronized(to){
from.withdraw(amt);
to.deposit(amt);
}
}
}
else if(toHash > fromHash){
synchronized(to){
synchronized(from){
from.withdraw(amt);
to.deposit(amt);
}
}
}
else {
synchronized(lock){
synchronized(from){
synchronized(to){
from.withdraw(amt);
to.deposit(amt);
}
}
}
}
}
看到这样的代码, 旺财倒吸了一口气,挠着头说:“搞什么鬼,转个账都这么麻烦!”




