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,对象上的同步不会阻止其他线程使用该对象。它只防止其他线程同时在同一对象上同步。