线程安全交换Java

Ari*_*deh 1 java multithreading thread-safety

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

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;
}
Run Code Online (Sandbox Code Playgroud)

我想让这个方法具有最高性能的线程安全(我想这意味着我们可能不会使方法同步),我们也要小心死锁,

我想到了以下解决方案:

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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在性能方面有没有更好的实施?顺便说一下,这个线程安全吗?

JB *_*zet 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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

但是,首先要对代码进行编译,并尊重Java命名约定.

  • 我不知道等待和通知如何与问题相关.没有理由等待,没有理由通知另一个线程. (3认同)
  • 这就是synchronized的作用:它会一直阻塞,直到监视器被释放.无需等待. (2认同)