错序死锁(Locking-ordering deadlock)是众多死锁情形中的一种,造成这种死锁的主要原因就是某些并发操作需要获取一个锁集合或其子集。
如下面的代码:
import java.util.concurrent.TimeUnit;
public
class LockOrderingDeadLock {
private Object lock1 = new Object();
private Object lock2 = new Object();
public void op1() {
synchronized(lock1) {
System.out.println("do sth in op1 with lock1...");
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {}
System.out.println("after sleep in op1");
synchronized(lock2) {
System.out.println("do sth in op1 with lock2...");
}
}
}
public void op2() {
synchronized(lock2) {
System.out.println("do sth in op2 with lock2...");
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {}
System.out.println("after sleep in op2");
synchronized(lock1) {
System.out.println("do sth in op2 with lock1...");
}
}
}
public static void main(String... args) {
final LockOrderingDeadLock test = new LockOrderingDeadLock();
new Thread() {
public void run() {
test.op1();
}
}.start();
new Thread() {
public void run() {
test.op2();
}
}.start();
}
}
在op1中,获取锁lock1后做了一些操作,而op2同时获取lock2后进行一些操作,当op1需要lock2的时候,op2尚未释放lock2,而op2一直等待lock1才能完成操作,于是就造成了死锁。示例中的死锁情况比较直观,两个锁是在同一个类中。而实际情况往往比这个复杂且难以发觉,如以下情形:
public void transferMoney(Account fromAccount,
Account toAccount,
DollarAmount amount)
throws InsufficientFundsException {
synchronized (fromAccount) {
synchronized (toAccount) {
if (fromAccount.getBalance().compareTo(amount) < 0)
throw new InsufficientFundsException();
else {
fromAccount.debit(amount);
toAccount.credit(amount);
}
}
}
}
当同时有两个调用:
A: transferMoney(myAccount, yourAccount, 10);
B: transferMoney(yourAccount, myAccount, 20);
A操作需要先个myAccount加锁,后给yourAccount加锁;而B要先给yourAccount加锁,后给myAccount加锁,这又带来了锁顺序问题,而锁的顺序是由外界输入确定的,这种就难以发觉。
解决这类死锁的根本思想就是设法保证多个锁的加锁顺序一致。