我有一个方法接收两个银行账户作为输入并交换它们的值:
Public void TransferAccount(AccountID id1, AccountID id2){
Account a1 = id1.GetAccount();
Account a2 = id2.GetAccount();
//Swap amounts.
Temp = a1.Balance;
a1.Balance = a2.Balance;
a2.Balance = Temp;
}
我想让这个方法是线程安全的,具有尽可能高的性能(我想这意味着我们可能不会让这个方法同步),我们也必须小心死锁,
我想到了以下解决方案:
Public void TransferAccount(AccountID id1, AccountID id2){
Account a1 = id1.GetAccount();
Account a2 = id2.GetAccount();
//Swap amounts.
synchronized(a1){
wait(a2);
synchronized(a2){
Temp = a1.Balance;
a1.Balance = a2.Balance;
a2.Balance = Temp;
}
}
}
在性能方面有没有更好的实现?顺便问一下,这完全是线程安全的吗?
最佳答案
您的代码容易出现死锁。如果一个线程调用 swap(a2, a1)
而另一个线程调用 swap(a1, a2)
,就会出现死锁。
您必须确保始终以相同的顺序锁定您的帐户。例如,假设所有帐户都由唯一 ID 标识,
public void swap(Account a1, Account a2) {
Account first = a1;
Account second = a2;
if (a1.getId().compareTo(a2.getId()) > 0) {
first = a2;
second = a1;
}
synchronized (first) {
synchronized (second) {
// swap the balances
}
}
}
另一个大问题是您使用公共(public)字段访问帐户余额。几乎不应该使用公共(public)字段,尤其是当一个对象被多个线程访问时。使用访问器方法,并确保它们已正确同步,否则另一个线程在交换后将看不到新余额。必须始终以同步方式访问每个共享状态。
但是对您的代码要做的第一件事是编译它,并遵守 Java 命名约定。
关于java - Java中的线程安全交换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16992210/