java - 怎么可能有竞争条件呢?

标签 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 锁定了它的 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/

相关文章:

.net - 如何避免以错误的顺序从 Process 类接收事件?

带有配置文件的 Java Spring Autowiring

java - gradle bootRun成功启动,但一段时间后断开连接

.net - 调用 UI 委托(delegate)会导致 UI 被隐藏

multithreading - C++0x线程问题

java - 为什么当我在此 java 代码中执行读取-更新-写入时不存在竞争条件?

Flash API的Java实现

java - 在 HashMap 中使用 keySet() 方法

java - volatile 关键字有什么用?

Python 服务文件缓存 Apache 竞态条件