故障排除和修复死锁

时间:2019-01-31 18:20:18

标签: java multithreading

我碰到这个问题,近日来到这里,我假设找到现在下面的代码僵局。我没有Java或多线程的经验,这就是为什么我在这里更好地理解问题的原因。

public class BankAccount {
  private final int customerId;
  private int balance;

  public BankAccount(int customerId, int openingBalance) {
    this.customerId = customerId;
    this.balance = openingBalance;
  }

  public void withdraw(int amount) throws OverdrawnException {
    if (amount > balance) {
      throw new OverdrawnException();
    }
    balance -= amount;
  }

  public void deposit(int amount) {
    balance += amount;
  }

  public int getCustomerId() {
    return customerId;
  }



  public int getBalance() {
    return balance;
  }
}


class TransferOperation extends Thread {
    int threadNum;

    TransferOperation(int threadNum) {
        this.threadNum = threadNum;
    }

    private void transfer(BankAccount fromAccount, BankAccount toAccount, int transferAmount) throws OverdrawnException {
        synchronized (fromAccount) {                    
            synchronized (toAccount) {
                fromAccount.withdraw(transferAmount);
                toAccount.deposit(transferAmount);
            }
        }
    }

    // ...
}

我有这样的上面一段代码。我想找到以上代码中可能发生死锁的位置。我认为它可能发生的唯一位置是在两个同步块中。我说的对吗?

如果是,有人可以帮助我了解为什么?我可以猜测,很可能是因为退出,存款保持一个线程等待另一个。但这是一个总的猜测,这就是为什么在这里寻求帮助。

如果我想防止死锁,我该如何在代码中解决死锁?

任何帮助表示赞赏。

2 个答案:

答案 0 :(得分:3)

您要先在fromAccount个对象上同步,然后在toAccount个对象上同步。

 想象一下,第一个线程使用X,Y调用传递方法,而同时另一个线程使用Y,X参数调用相同的方法-这会导致死锁。

第一个线程“锁定” X,第二个线程“锁定” Y,然后第一个线程试图锁定Y,后者已经被第二个线程锁定。
但是第二个线程正在尝试锁定已经被第一个线程锁定的X。
这是死锁

答案 1 :(得分:1)

以下是我可能想到的解决方案。

可能的解决方案:

  1. transfer()内始终先锁定ID较小的帐户,然后再锁定ID较大的帐户。
    检查以下内容以查看其工作原理:Would you explain lock ordering?

  2. 将整个传输方式标记为synchronized
    它将使它成为单线程的,可以解决此问题,但是对于大量帐户来说速度很慢。

  3. 将请求封装为一个对象,将其发送到FIFO队列,然后一个线程处理器可以处理它,每个请求都在事务中处理。

  4. (根据解决方案2进行了改进),在内存中维护一组正在处理的请求的帐户ID。

    • 如果请求的2个ID不在ID集中,则使用现有或新的并行线程进行处理。
    • 否则,将其移至队列末尾或以其他方式延迟其处理。

    (此实现可能很复杂,但是正确编写起来并不容易)

  5. 对请求进行分组。
    在每个组中,任何ID仅出现一次,然后逐个处理组。
    一次只能处理一组,但要处理多个线程。
    (这与第3种解决方案有点相似,但对于正确实现而言并非易事)