怎么会有竞争条件?
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
上进行任何同步以使其等待。
当所有帐户都同步时,为什么我的代码中会出现竞争条件?
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
上进行任何同步以使其等待。