Java多線程同步1——使用synchronized 代碼塊

關于多線程同步問題我們可以借用一個銀行取錢的實例來說明問題。

在這里我們簡單的建立一個類來代表銀行賬戶,代碼如下

public class Account {

// 賬號

private String accountNo;

//余額

private double balance;

public Account(){}

// 構造器

public Account(String accountNo , double balance)

{

this.accountNo = accountNo;

this.balance = balance;

}

// accountNo的setter和getter方法

public void setAccountNo(String accountNo)

{

this.accountNo = accountNo;

}

public String getAccountNo()

{

return this.accountNo;

}

// balance的setter和getter方法

public void setBalance(double balance)

{

this.balance = balance;

}

public double getBalance()

{

return this.balance;

}

// 下面兩個方法根據accountNo來重寫hashCode()和equals()方法

public int hashCode()

{

return accountNo.hashCode();

}

public boolean equals(Object obj)

{

if(this == obj)

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;

private double drawAmount;

public DrawThread(String name , Account account

, double drawAmount)

{

super(name);

this.account = account;

this.drawAmount = drawAmount;

}

public void run()

{

if (account.getBalance() >= drawAmount)

{

System.out.println(getName()

+ "取錢成功!吐出鈔票" + drawAmount);

try

{

Thread.sleep(1);

}

catch (InterruptedException ex)

{

ex.printStackTrace();

}

account.setBalance(account.getBalance() - drawAmount);

System.out.println("\t余額為:" + account.getBalance());

}

else

{

System.out.println(getName() + "取錢失敗!余額不足");

}

}

}


在建立一個測試類模仿2個人對同一個賬戶進行取錢

public class DrawTest

{

public static void main(String[] args)

{

Account acct = new Account("1234567" , 1000);

new DrawThread("甲" , acct , 800).start();

new DrawThread("乙" , acct , 800).start();

}

}

運行結果有可能出現如下圖所示的情況



問題來了:賬戶余額只有1000時取出了1600塊,而且賬戶余額出現了負值,這不是我們希望得到的結果。


這是因為run()方法的方法體不具備同步安全性——程序中有兩個并發線程在修改Account對象,

為了解決這個問題,java多線程引入了同步監視器來解決這個問題,使用同步監視器的通用方法就是同步代碼塊。

synchronized (obj){

}

上面語法格式中的synchronized括號里面的obj就是同步監視器,上面代碼的含義是:線程開始執行

同步之前,必須先獲得同步監視器的鎖定
將上面的代碼做如下修改


public class DrawThread extends Thread

{

private Account account;

private double drawAmount;

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(1);

}

catch (InterruptedException ex)

{

ex.printStackTrace();

}

account.setBalance(account.getBalance() - drawAmount);

System.out.println("\t余額為: " + account.getBalance());

}

else

{

System.out.println(getName() + "取錢失敗!余額不足");

}

}

}

}

運行代碼得到如下結果:


最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容