多线程编程常常会出现各种安全问题,银行取钱是一个经典的线程安全问题。

public class Account {
    private String accountNo;
    private double balance;
    public Account() {}
    public Account(String accountNo, double balance) {
        this.accountNo = accountNo;
        this.balance = balance;
    }
    public String getAccountNo() {
        return accountNo;
    }
    public void setAccountNo(String accountNo) {
        this.accountNo = accountNo;
    }
    public double getBalance() {
        return balance;
    }
    public void setBalance(double balance) {
        this.balance = balance;
    }
    @Override
    public int hashCode() {
        return accountNo.hashCode();
    }
    @Override
    public boolean equals(Object obj) {
        if(obj == this)
            return true;
        if(obj != null && obj.getClass() == Account.class) {
            Account target = (Account)obj;
            return target.getAccountNo().equals(accountNo);
        }
        return false;
    }
}

public class DrawThread extends Thread {
    private Account account;
    // The amount of money that client want to draw
    private double drawAmount;

    public DrawThread(String name, Account account, double drawAmount) {
        super(name);
        this.account = account;
        this.drawAmount = drawAmount;
    }

    @Override
    public void run() {
        if (account.getBalance() >= drawAmount) {
            System.out.println(getName() + " draw money:" + drawAmount);
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            account.setBalance(account.getBalance() - drawAmount);
            System.out.println("The blance is:" + account.getBalance());
        } else {
            System.out.println(getName() + "The blance is not enough!");
        }
    }
}

public class DrawTest {
    public static void main(String[] args) {
        Account acct = new Account("123", 10000);
        new DrawThread("A", acct, 8000).start();
        new DrawThread("B", acct, 8000).start();
    }
}

上面的程序可能出现各种结果,可运行观察之。其中一个结果如下,账户被取了比余额更多的钱,这显然是不可接受的。

A draw money:8000.0
B draw money:8000.0
The blance is:2000.0
The blance is:-6000.0