我正在尝试使用可重入锁激发共享阵列中的死锁。
class SharedArray {
private int ff[];
private Lock keys[];
public SharedArray(int n){
ff = new int[n];
keys = new ReentrantLock[n];
for(int j = 0; j < n; j++){
ff[j] = (int)(Math.random()*100);
keys[j] = new ReentrantLock();
}
}
void swap(int j, int k) {
keys[j].lock(); keys[k].lock();
int t = ff[j]; ff[j] = ff[k]; ff[k] = t;
keys[j].unlock(); keys[k].unlock();
}
}
这里,交换方法很容易出现死锁。例如,如果线程1是swap(7,4),同时线程2是swap(4,7),则会引发死锁。
如何防止死锁。需要什么样的重构。我尝试使用同步,但我正在寻找一种可能的可靠方法来解决该问题。
synchronized void swap(int j, int k) {
keys[j].lock(); keys[k].lock();
int t = ff[j]; ff[j] = ff[k]; ff[k] = t;
keys[j].unlock(); keys[k].unlock();
}
答案 0 :(得分:0)
如何防止死锁?
防止死锁的一种方法是确保任何获得相同两个锁的线程始终以相同的顺序获取它们。
void swap(int j, int k) {
int first = Math.min(j, k);
int second = Math.max(j, k);
keys[first].lock(); keys[second].lock();
int t = ff[j]; ff[j] = ff[k]; ff[k] = t;
keys[second].unlock(); keys[first].unlock();
}
答案 1 :(得分:0)
您要采用锁定顺序。如果您每次以可预测的顺序锁定,则可以防止死锁。
在Java Concurrency in Practice中发现,您可以看到一个有关如何实现此目的的示例:
public void transferMoney(final Account fromAcct, final Account toAcct, final DollarAmount amount)
throws InsufficientFundsException {
class Helper {
public void transfer() throws InsufficientFundsException {
if (fromAcct.getBalance().compareTo(amount) < 0)
throw new InsufficientFundsException();
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();
}
}
}
}
}
https://pdfs.semanticscholar.org/3650/4bc31d3b2c5c00e5bfee28ffc5d403cc8edd.pdf,搜索清单10.3。诱导锁定顺序以避免死锁。