怎么会有竞争条件?

时间:2016-08-06 12:44:11

标签: java multithreading race-condition synchronized

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

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将其锁定来自帐户(托马斯),而transfer2将其锁定来自帐户(mathias),所以他们都不应该陷入死锁?

2 个答案:

答案 0 :(得分:1)

问题是代码toAccount.book(amount)没有使用同步保护运行。

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

任何帐户上运行的任何线程都必须首先锁定(同步)该帐户,无论它是加号还是减号。

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

答案 1 :(得分:1)

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

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