【发布时间】:2021-06-25 07:32:29
【问题描述】:
我有 2 个帐户和 2 个线程。 1个线程将钱从1个账户转移到2个账户,2个线程将钱从2个账户转移到1个账户,当然如果有足够的钱。我需要意识到死锁情况并解决确认安全转移的死锁情况。这是我现在所拥有的:
Account.java
public class Account {
private /*volatile*/ long balance;
public Account() {
this(0L);
}
public Account(long balance) {
this.balance = balance;
}
public long getBalance() {
return balance;
}
public synchronized void deposit(long amount) {
checkAmountNonNegative(amount);
balance += amount;
}
public synchronized void withdraw(long amount) {
checkAmountNonNegative(amount);
if (balance < amount) {
throw new IllegalArgumentException("not enough money");
}
balance -= amount;
}
private static void checkAmountNonNegative(long amount) {
if (amount < 0) {
throw new IllegalArgumentException("negative amount");
}
}
}
Main.java
public class Main {
public static void main(String[] args) {
Account first = new Account(1_000_000);
Account second = new Account(1_000_000);
TransferThread thread1 = new TransferThread(first, second, 2000);
TransferThread thread2 = new TransferThread(second, first, 2000);
CompletableFuture.allOf(
CompletableFuture.runAsync(thread1),
CompletableFuture.runAsync(thread2)
).join();
System.out.println(first.getBalance());
System.out.println(second.getBalance());
}
}
TransferThread.java
public class AccountThread implements Runnable {
private final Account from;
private final Account to;
private final long amount;
public AccountThread(Account from, Account to, long amount) {
this.from = from;
this.to = to;
this.amount = amount;
}
@Override
public void run() {
for (int i = 0; i < 2000; i++) {
// my realization
try {
if (from.getBalance() < 0) {
throw new InsufficientFundsException();
} else {
from.deposit(amount);
to.withdraw(amount);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
我决定将同步到存款和取款两种方法以安全转移。但怀疑用方法run实现。我有正确的实施吗?如果没有,将不胜感激解释和纠正。
【问题讨论】:
-
我认为您需要将
try-catch放入具有相同监视器对象的synchronized块中。在同步方法的情况下,在对象上获取锁。在这里,您有两个帐户,因此有两个单独的锁。 -
同样先提款,如果成功则存入目标账户。
-
@onkarruikar 老实说,try-catch 没有让你明白,你能给我举个例子吗?
-
汇款是死锁问题的典型例子。您不需要在 Account 类中使用 volatile 或 synchronize 或其他任何东西。您应该在转移前锁定两个帐户,然后释放它们。为了避免死锁,您必须引入某种排序并按顺序锁定一对帐户,正如@StephenC 所述
标签: java multithreading