Java 避免多个事务对象死锁的最佳方法?
我在寻找死锁示例时偶然发现了以下代码:Java 避免多个事务对象死锁的最佳方法?,java,multithreading,concurrency,synchronized,Java,Multithreading,Concurrency,Synchronized,我在寻找死锁示例时偶然发现了以下代码: package com.example.thread.deadlock._synchronized; public class BankAccount { double balance; int id; BankAccount(int id, double balance) { this.id = id; this.balance = balance; } void withdr
package com.example.thread.deadlock._synchronized;
public class BankAccount {
double balance;
int id;
BankAccount(int id, double balance) {
this.id = id;
this.balance = balance;
}
void withdraw(double amount) {
// Wait to simulate io like database access ...
try {Thread.sleep(10l);} catch (InterruptedException e) {}
balance -= amount;
}
void deposit(double amount) {
// Wait to simulate io like database access ...
try {Thread.sleep(10l);} catch (InterruptedException e) {}
balance += amount;
}
static void transfer(BankAccount from, BankAccount to, double amount) {
synchronized(from) {
from.withdraw(amount);
synchronized(to) {
to.deposit(amount);
}
}
}
public static void main(String[] args) {
final BankAccount fooAccount = new BankAccount(1, 100d);
final BankAccount barAccount = new BankAccount(2, 100d);
new Thread() {
public void run() {
BankAccount.transfer(fooAccount, barAccount, 10d);
}
}.start();
new Thread() {
public void run() {
BankAccount.transfer(barAccount, fooAccount, 10d);
}
}.start();
}
}
如何更改
transfer
方法,使其不会导致死锁?第一个想法是为所有帐户创建一个共享锁,但这当然会扼杀所有并发性。那么,有没有一种好方法可以只锁定一个事务中涉及的两个帐户,而不影响其他帐户?分别使用两个同步块,而不是嵌套块
synchronized(from){
from.withdraw(amount);
}
synchronized(to){
to.deposit(amount);
}
因此,在调用
from.draw(amount)
之后,在尝试将锁定到之前,将释放对from
的锁定,分别使用两个同步块,而不是嵌套块
synchronized(from){
from.withdraw(amount);
}
synchronized(to){
to.deposit(amount);
}
因此,在调用from.draw(amount)
后,在尝试将锁定到之前,将释放对from
的锁定,以避免在多锁情况下出现死锁的一种方法是始终以相同的顺序锁定对象
在本例中,这意味着您将为所有BankAccount
对象创建一个总排序。幸运的是,我们有一个可以使用的id,因此您可以始终先锁定较低的id,然后(在另一个同步块中)锁定较高的id
这假设没有具有相同ID的BankAccount对象,但这似乎是一个合理的假设。在多锁情况下避免死锁的一种方法是始终以相同的顺序锁定对象
在本例中,这意味着您将为所有BankAccount
对象创建一个总排序。幸运的是,我们有一个可以使用的id,因此您可以始终先锁定较低的id,然后(在另一个同步块中)锁定较高的id
这假设没有具有相同ID的BankAccount
对象,但这似乎是一个合理的假设。如果一个成员在交易过程中因为另一个交易而没有钱,那么使用两个同步块会出现问题您确实意识到这不是一个交易,对吗?如果一个成员在交易过程中因为另一个交易而没有钱,那么使用2个同步块会出现问题。你意识到这不是一个交易,对吗?