多線程同步---synchronize

       在項目中我們經常遇到這樣一種情況:兩個人同時操作數據庫,導致數據異常。針對於數據庫級別我們採用鎖機制,還有一種方法使規定我們方法調用的權限,當你在使用這個資源的時候別人是不允許使用的,在多線程中只需要一個修飾詞就可以實現:synchronize。
      第一步: 下面我們採用銀行取錢的場景來代碼實現
Account類:
public class Account {
    private String accountNo;
    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;
    }
    private double balance;
    public Account(){
        
    }
    
public Account(String accountNo,double balance){
        this.accountNo=accountNo;
        this.balance=balance;
    }
public int hashCode(){
    return accountNo.hashCode();
}
public boolean equals(Object obj){
    if(obj !=null && obj.getClass()==Account.class){
        Account target =(Account)obj;
        return target.getAccountNo().equals(accountNo);
    }
    return false;
}
/*public synchronized void draw(double drawAmount){
    
    if(balance >=drawAmount){
        System.out.println(Thread.currentThread().getName()+"取錢成功,吐出鈔票"+drawAmount);
        
        try {
            Thread.sleep(1);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
        balance-=drawAmount;
        System.out.println("\t餘額爲:"+balance);
        
    }else{
        System.out.println(Thread.currentThread().getName()+"取錢失敗!餘額不足!");
    }
}
*/
}



線程類:
public class DrawThread extends Thread{
    
    private Account account;
    private double drawAmount;
    
    public double getDrawAmount() {
        return drawAmount;
    }
    public void setDrawAmount(double drawAmount) {
        this.drawAmount = drawAmount;
    }
    public Account getAccount() {
        return account;
    }
    public void setAccount(Account account) {
        this.account = account;
    }
    
    public DrawThread(String name, Account account, double drawAmount){
        
        super(name);
        this.account=account;
        this.drawAmount=drawAmount;
        
    }
    
    public void run(){
        
       // synchronized(account){
        if(account.getBalance() >=drawAmount){
            System.out.println(getName()+"取錢成功,吐出鈔票"+drawAmount);
            
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            
            account.setBalance(account.getBalance()-drawAmount);
            System.out.println("\t餘額爲:"+account.getBalance());
            
        }else{
            System.out.println(getName()+"取錢失敗!餘額不足!");
        }
    }
        /*account.draw(drawAmount);*/
    
   // }
}



client進行測試:
public class TestDraw {
    public static void main(String[] args) {
        
        Account acct= new Account("1234567",1000);
        
        new DrawThread("甲",acct,800).start();
        new DrawThread("乙",acct,800).start();
    }
}


多次執行出現的結果:


     第二步:我們給我們需要執行的邏輯加上synchronize
   run方法下面的synchronized(account)解開註釋繼續執行,查看結果。
多次執行結果只有:

    解析:當我們加上synchronize修飾詞的時候相當於把account類給鎖住了,本線程使用account的時候,其他線程不能對account進行編輯。
    第三步:給Account加一個有 synchronize修飾的draw方法,即將代碼中的draw註釋解除,drawThread方法中也需要改變:
public synchronized void draw(double drawAmount){
    
    if(balance >=drawAmount){
        System.out.println(Thread.currentThread().getName()+"取錢成功,吐出鈔票"+drawAmount);
        
        try {
            Thread.sleep(1);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
        balance-=drawAmount;
        System.out.println("\t餘額爲:"+balance);
        
    }else{
        System.out.println(Thread.currentThread().getName()+"取錢失敗!餘額不足!");
    }
}
DrawThread中的run方法:
public void run(){
        account.draw(drawAmount);
    }
執行結果:

總結:
   關於同步方法修飾詞synchronize的使用我們分三步來走,第一步,不加修飾詞,多次執行會發現偶爾出現錯誤。第二步,當給Accout實體加入synchronize修飾詞後發現多次執行也不會發生錯誤。第三步,給Account實體加一個有synchronize修飾的draw方法,大家會發現這樣雖然效果和第二步是一直的,但是在靈活性上明顯是第三步的修改要好很多。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章