1

我有一个方法,它接收两个银行账户作为输入并交换它们的值:

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;
        }
    }
}

在性能方面有更好的实现吗?顺便说一句,这是线程安全的吗?

4

1 回答 1

8

您的代码可能会出现死锁。如果一个线程调用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
        }
    }
}

另一个大问题是您使用公共字段访问帐户的余额。公共字段几乎不应该被使用,尤其是当一个对象被多个线程访问时。使用访问器方法,并确保它们正确同步,否则另一个线程在交换后将看不到新余额。必须始终以同步的方式访问每个共享状态。

但是对您的代码做的第一件事是让它编译,并尊重 Java 命名约定。

于 2013-06-07T21:21:32.873 回答