java - Java中的线程安全交换

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

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

我想到了以下解决方案:

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/

相关文章:

java - LinkedBlockingQueue 和工作线程 - 这段代码线程安全吗?

java - Vaadin:从菜单项中删除标题

java - 在java中链接对象引用

java - 如何判断OpenJDK是否安装了调试符号

c++ - 尽管有线程,Qt GUI 仍挂起

Ruby ||= 运算符线程安全

java - HtmlUnit:每个线程一个 WebClient - 它是线程安全的吗?

java - 避免使用 try-catch 语句的充分理由

python - 从线程发出时,Flask Socket.io 不起作用

multithreading - Delphi:如何从 idHTTPServer.OnCommandGet 方法在主线程中执行过程