怎么会有竞争条件?

How can there be a race condition?

当所有帐户都同步时,为什么我的代码中会出现竞争条件?

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) 没有 运行 同步保护。

所以从技术上讲,thread1 持有 thomasAccount 的锁并且 thread2 持有 mathiasAccount 的锁,但 thread2 仍然 运行 同时预订 thomasAccount线程 1 运行 在 thomasAccount 上的书的时间。这可能会导致不一致,因为其中一个线程可以忽略第二个线程的结果。

简单地说,任何线程操作任何账户都必须首先锁定(同步)账户,无论是正负。

为避免死锁,使帐户具有可比性(或使用帐户的某些id)并始终按升序锁定帐户。或者您可以为此使用散列,但如果散列相同,则需要一些全局锁。

您的 run 方法仅在 fromAccount 上同步,而不是 toAccount。未同步的代码不会被同步代码阻塞;试图访问某物的两个线程必须 两者 同步才能序列化访问。

因此您的 run 方法不仅必须在 fromAccount 上同步,而且还必须在 toAccount 上同步,以便在 toAccount 上进行任何同步以使其等待。