package com.justalk.javademo.deadlock;
import org.jetbrains.annotations.NotNull;
import java.util.Random;
public class DemonstrateDeadLock {
public static class InsufficientFundsException extends Exception { }
public static class Account {
public String accountName;
public Account(String accountName) {
this.accountName = accountName;
}
DollarAmount dollarAmount = new DollarAmount(10_000);
public DollarAmount getBalance() {
return dollarAmount;
}
public void debit(DollarAmount amount) throws InterruptedException {
System.out.println(String.format("%S减少:%d美金",accountName,amount.cash));
dollarAmount.cash -= amount.cash;
System.out.println(String.format("%S还有金额:%d美金",accountName,dollarAmount.cash));
Thread.sleep(500);
}
public void credit(DollarAmount amount) throws InterruptedException {
System.out.println(String.format("%S增加:%d美金",accountName,amount.cash));
dollarAmount.cash += amount.cash;
System.out.println(String.format("%S还有金额:%d美金",accountName,dollarAmount.cash));
Thread.sleep(500);
}
}
public static class DollarAmount implements Comparable<DollarAmount> {
private int cash;
public DollarAmount(int cash) {
this.cash = cash;
}
@Override
public int compareTo(@NotNull DollarAmount dollarAmount) {
return cash - dollarAmount.cash;
}
}
private static final Object tieLock = new Object();
private static final int NUM_THREADS = 20;
private static final int NUM_COUNT = 2;
private static final int NUM_DO = 10_000;
public static void main(String[] args) {
final Random random = new Random();
final Account[] accounts = new Account[NUM_COUNT];
for (int i = 0; i < accounts.length; i++) {
accounts[i] = new Account("账户"+i);
}
class TransferThread extends Thread {
@Override
public void run() {
for (int i = 0; i < NUM_DO; i++) {
int fromAcct = random.nextInt(NUM_COUNT);
int toAcct = random.nextInt(NUM_COUNT);
DollarAmount amount = new DollarAmount(random.nextInt(1000));
try {
try {
transferMoney(accounts[fromAcct],accounts[toAcct],amount);
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("发生了线程中断");
}
} catch (InsufficientFundsException e) {
System.out.println("转账金额不正确");
e.printStackTrace();
}
}
}
private void transferMoney(final Account fromAcct,
final Account toAcct,
final DollarAmount amount)
throws InsufficientFundsException, InterruptedException {
class Helper {
public void transfer() throws InsufficientFundsException, InterruptedException {
int detal = fromAcct.getBalance().compareTo(amount);
System.out.println(String.format("比较的差值是:%d",detal));
if (detal < 0) {
throw new InsufficientFundsException();
} else {
System.out.println(String.format("fromAcct:%s,toAcct:%s",fromAcct.accountName,toAcct.accountName));
fromAcct.debit(amount);
toAcct.credit(amount);
}
}
}
int fromHash = System.identityHashCode(fromAcct);
int toHash = System.identityHashCode(toAcct);
if (fromHash < toHash) {
synchronized (fromAcct) {
synchronized (toAcct) {
new Helper().transfer();
}
}
} else if (fromHash > toHash) {
synchronized (toAcct) {
synchronized (fromAcct) {
new Helper().transfer();
}
}
} else {
synchronized (tieLock) {
synchronized (fromAcct) {
synchronized (toAcct) {
new Helper().transfer();
}
}
}
}
}
}
for (int i = 0; i < NUM_THREADS; i++) {
new TransferThread().start();
}
}
}