当所有帐户都同步时,为什么我的代码中会存在竞争条件?
class Transfer implements Runnable {
Konto fromAccount;
Konto toAccount;
Integer amount;
public void run() {
synchronized (fromAccount) {
if (fromAccount.book(-amount)) {
toAccount.book(amount);
}
}
}
}
public class Main {
public static void main(String[] args) throws InterruptedException
Account thomas = new Account(1234, 100);
Account mathias = new Account(5678, 100);
Thread transfer1 = new Thread(new Transfer(80, thomas, mathias));
Thread transfer2 = new Thread(new Transfer(95, mathias, thomas));
transfer1.start();
transfer2.start();
transfer1.join();
transfer2.join();
}
根据我的理解,transfer1 锁定了它的 fromAccount (thomas),transfer2 锁定了它的 fromAccount (mathias),所以他们不应该都陷入死锁吗?
最佳答案
问题在于代码 toAccount.book(amount)
未在同步保护下运行。
因此从技术上讲,线程 1 可能会持有 thomasAccount
的锁,而线程 2 可能会持有 mathiasAccount
的锁,但线程 2 仍会在 thomasAccount
上运行书籍,地址为线程 1 在 thomasAccount 上运行书籍的同时。这可能会导致不一致,因为其中一个线程可以忽略第二个线程的结果。
简单来说,在任何帐户上操作的任何线程都必须首先锁定(同步)该帐户,无论该帐户是正数还是负数。
为了避免死锁,请使帐户具有可比性(或使用帐户的某些 ID)并始终按升序锁定帐户。或者您可以使用散列来实现此目的,但如果散列相同,则需要一些全局锁。
关于java - 怎么可能有竞争条件呢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38804436/