1. 程式人生 > >經典的同步問題(銀行取錢)

經典的同步問題(銀行取錢)

銀行取錢問題是非常經典的同步問題,如果不採用同步方法,可能也不會發生錯誤,但就是那小概率事件就可以稱之為BUG吧。
沒有使用同步方法的程式碼如下:

public class ErrorTest{
    public static void main(String[] args)
    {
        user ur = new user(1000,"賬戶");
        new errorThread(800,"甲",ur).start();
        new errorThread(800,"乙",ur).start();
    }       
}
class user
{
    private
int balance; private String name; public user(int balance,String name) { this.balance = balance; this.name = name; } public int getBalance() { return balance; } public void setBalance(int balance) { this.balance = balance; } public
String getName() { return name; } public void setName(String name) { this.name = name; } @Override public int hashCode() { return name.hashCode(); } @Override public boolean equals(Object o) { if (o == this) { return
true; } if (o.getClass() == user.class && o !=null ) { user ur = (user)o; if (ur.name.equals(name)) { return true; } } return false; } } class errorThread extends Thread { private int money; //private String name; private user ur; public errorThread(int money,String name,user ur) { super(name); this.money = money; this.ur = ur; } @Override public void run() { if (ur.getBalance() >= money) { System.out.println(getName()+"成功取出鈔票"+money); ur.setBalance(ur.getBalance()-money); System.out.println("剩下的錢:"+ur.getBalance()); try{ sleep(10);//這裡用了sleep(),強制執行緒切換 }catch(InterruptedException ie) { ie.printStackTrace(); } } else { System.out.println(getName()+"餘額不足,取錢失敗"); } } }

執行你結果如下:
甲成功取出鈔票800
乙成功取出鈔票800
剩下的錢:200
剩下的錢:-600
這樣銀行豈不會陪哭了?哈哈哈哈。
因此,必須使用同步方法,通常情況下使用被併發訪問的共享資源作為同步監視器,程式碼如下:

public class ErrorTest{
    public static void main(String[] args)
    {
        user ur = new user(1000,"賬戶");
        new errorThread(800,"甲",ur).start();
        new errorThread(800,"乙",ur).start();
    }       
}
class user
{
    private int balance;
    private String name;
    public user(int balance,String name)
    {
        this.balance = balance;
        this.name = name;
    }
    public int getBalance() {
        return balance;
    }
    public void setBalance(int balance) {
        this.balance = balance;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public int hashCode()
    {
        return name.hashCode();
    }
    @Override
    public boolean equals(Object o)
    {
        if (o == this)
        {
            return true;
        }
        if (o.getClass() == user.class && o !=null )
        {
            user ur = (user)o;
            if (ur.name.equals(name))
            {
                return true;
            }
        }
        return false;
    }   
}
class errorThread extends Thread
{
    private int money;
    //private String name;
    private user ur;
    public errorThread(int money,String name,user ur)
    {
        super(name);
        this.money = money;
        this.ur = ur;
    }
    @Override
    public void run()
    {
        synchronized(ur)
        {
            if (ur.getBalance() >= money)

            {
                System.out.println(getName()+"成功取出鈔票"+money);
                ur.setBalance(ur.getBalance()-money);
                System.out.println("剩下的錢:"+ur.getBalance());
                try{
                    sleep(10);
                }catch(InterruptedException ie)
                {
                    ie.printStackTrace();
                }
            }

            else
            {
                System.out.println(getName()+"餘額不足,取錢失敗");
            }
        }
    }
}

執行結果如下:
甲成功取出鈔票800
剩下的錢:200
乙餘額不足,取錢失敗
這樣符合”加鎖-修改-釋放鎖“的邏輯,銀行再也不用擔心虧錢了,嘻嘻。