Java 怎么会有比赛条件?

Java 怎么会有比赛条件?,java,multithreading,race-condition,synchronized,Java,Multithreading,Race Condition,Synchronized,当所有帐户都同步时,为什么我的代码中会有竞争条件 class Transfer implements Runnable { Konto fromAccount; Konto toAccount; Integer amount; public void run() { synchronized (fromAccount) { if (fromAccount.book(-amount)) {

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

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),因此它们不应该都以死锁告终吗?

问题是代码
到Account.book(amount)
不能与同步保护一起运行

因此,从技术上讲,thread1可能会锁定
thomasAccount
,thread2可能会锁定
mathiasAccount
,但thread2仍然在
thomasAccount
上运行book,而thread1在
thomasAccount
上运行book。这可能导致不一致,因为其中一个线程可以忽略第二个线程的结果

简单地说,在任何帐户上运行的任何线程都必须首先锁定(同步)该帐户,不管它是加号还是减号


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

您的
run
方法仅在
fromAccount
上同步,而不是
到Account
上同步。未同步的代码不会被同步代码阻止;试图访问某个对象的两个线程必须都在该对象上同步,以便序列化访问


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

是否存在死锁或竞争条件?你两个都提到了,但它们是不同的。在我看来,您可能有一场竞争,但快速看一眼就不会出现死锁。感谢您的回答,但我仍然不完全理解一件事:如果thread1锁定了
thomasAccount
,thread2如何在
thomasAccount
上运行book?thread2仅在尝试获取相同的锁时才会停止。调用
book()
本身不会执行锁定。再次感谢,您在这里真的帮了我的忙!因此,如果我理解正确,锁定的对象仍然可以从其他线程访问,例如通过方法调用,只要它不试图获取对它的锁定。是吗?@Numb3rs:没错。只有当方法被标记为已同步时,它才会在方法执行之前获得对象上的锁(
this
)。@Numb3rs,对象上的同步不会阻止其他线程使用该对象。它只防止其他线程同时在同一对象上同步。