Java同步代碼塊解決銀行取錢(qián)的安全問(wèn)題實(shí)例分析
本文實(shí)例講述了Java同步代碼塊解決銀行取錢(qián)的安全問(wèn)題。分享給大家供大家參考,具體如下:
一 點(diǎn)睛
為了解決類(lèi)似銀行取錢(qián)這類(lèi)安全問(wèn)題,Java的多線程支持引入了同步監(jiān)視器來(lái)解決這個(gè)問(wèn)題,使用同步監(jiān)視器的通用方法是同步代碼塊。同步代碼塊的語(yǔ)法格式是:
synchronized(obj)
{
//此處代碼塊就是同步代碼塊。
}
上面語(yǔ)法格式中種的obj就是同步監(jiān)視器,上面代碼的含義是:線程開(kāi)始執(zhí)行同步代碼塊之前,必須先獲得對(duì)同步監(jiān)視器的鎖定。
任何時(shí)刻只能由一個(gè)線程獲得對(duì)同步監(jiān)視器的鎖定,當(dāng)同步代碼塊執(zhí)行完成后,該線程會(huì)釋放對(duì)該同步監(jiān)視器的鎖定。
雖然Java程序允許使用任何對(duì)象作為同步監(jiān)視器,但想一下同步監(jiān)視器的目的:阻止兩個(gè)線程對(duì)同一共享資源進(jìn)行并發(fā)訪問(wèn),因此通常推薦使用可能被并發(fā)訪問(wèn)的共享資源作為同步監(jiān)視器。
二 代碼
1 定義一個(gè)賬戶類(lèi)
public class Account
{
// 封裝賬戶編號(hào)、賬戶余額的兩個(gè)成員變量
private String accountNo;
private double balance;
public Account(){}
// 構(gòu)造器
public Account(String accountNo , double balance)
{
this.accountNo = accountNo;
this.balance = balance;
}
// 此處省略了accountNo和balance的setter和getter方法
// 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;
}
// 下面兩個(gè)方法根據(jù)accountNo來(lái)重寫(xiě)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;
}
}
2 定義一個(gè)取錢(qián)線程
public class DrawThread extends Thread {
// 模擬用戶賬戶
private Account account;
// 當(dāng)前取錢(qián)線程所希望取的錢(qián)數(shù)
private double drawAmount;
public DrawThread(String name, Account account, double drawAmount) {
super(name);
this.account = account;
this.drawAmount = drawAmount;
}
// 當(dāng)多條線程修改同一個(gè)共享數(shù)據(jù)時(shí),將涉及數(shù)據(jù)安全問(wèn)題。
public void run() {
synchronized (account) {
// 賬戶余額大于取錢(qián)數(shù)目
if (account.getBalance() >= drawAmount) {
// 吐出鈔票
System.out.println(getName() + "取錢(qián)成功!吐出鈔票:" + 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() + "取錢(qián)失??!余額不足!");
}
}
}
}
3 測(cè)試主類(lèi)
public class DrawTest
{
public static void main(String[] args)
{
// 創(chuàng)建一個(gè)賬戶
Account acct = new Account("1234567" , 1000);
// 模擬兩個(gè)線程對(duì)同一個(gè)賬戶取錢(qián)
new DrawThread("甲" , acct , 800).start();
new DrawThread("乙" , acct , 800).start();
}
}
三 運(yùn)行
甲取錢(qián)成功!吐出鈔票:800.0
余額為: 200.0
乙取錢(qián)失敗!余額不足!
四 說(shuō)明
使用synchronized將run()方法里的方法體修改為同步代碼塊,該同步代碼塊的同步監(jiān)視器是account對(duì)象,這樣的做法符合“加鎖->修改->釋放鎖”的邏輯,任何線程在修改指定資源之前,首先對(duì)該資源加鎖,在加鎖期間其他線程無(wú)法修改該資源,當(dāng)該線程修改完成后,該線程釋放對(duì)該資源的鎖定。通過(guò)這種方式就可以保證并發(fā)線程任一時(shí)刻只有一個(gè)線程可以進(jìn)入修改共享資源的代碼區(qū)(也稱(chēng)臨界區(qū)),所以同一時(shí)刻最多只有一個(gè)線程處于臨界區(qū),從而保證線程的安全。
更多java相關(guān)內(nèi)容感興趣的讀者可查看本站專(zhuān)題:《Java面向?qū)ο蟪绦蛟O(shè)計(jì)入門(mén)與進(jìn)階教程》、《Java數(shù)據(jù)結(jié)構(gòu)與算法教程》、《Java操作DOM節(jié)點(diǎn)技巧總結(jié)》、《Java文件與目錄操作技巧匯總》和《Java緩存操作技巧匯總》
希望本文所述對(duì)大家java程序設(shè)計(jì)有所幫助。
相關(guān)文章
logback?OutputStreamAppender高效日志輸出源碼解析
這篇文章主要介紹了為大家logback?OutputStreamAppender日志輸出效率提升示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10
IDEA導(dǎo)入jar包的完整實(shí)現(xiàn)步驟
由于導(dǎo)入jar包項(xiàng)目存在很多不確定的問(wèn)題,導(dǎo)致每次都需要調(diào)試、配置好多遍,對(duì)此特意記錄下來(lái),這篇文章主要給大家介紹了關(guān)于IDEA導(dǎo)入jar包的相關(guān)資料,需要的朋友可以參考下2024-01-01
Spring Cloud如何使用Feign構(gòu)造多參數(shù)的請(qǐng)求
這篇文章主要介紹了Spring Cloud如何使用Feign構(gòu)造多參數(shù)的請(qǐng)求,以GET以及POST方法的請(qǐng)求為例進(jìn)行講解,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-03-03
System.identityHashCode和hashCode的區(qū)別及說(shuō)明
String調(diào)用hashCode()和System.identityHashCode()返回值不同是因?yàn)镾tring重寫(xiě)了hashCode()方法,而System.identityHashCode()返回對(duì)象的內(nèi)存地址哈希值;Test調(diào)用兩個(gè)方法返回值相同是因?yàn)門(mén)est沒(méi)有重寫(xiě)hashCode()方法,因此兩者調(diào)用底層的JVM_IHashCode方法返回相同值2024-11-11
JAVA實(shí)現(xiàn)將磁盤(pán)中所有空文件夾進(jìn)行刪除的代碼
這篇文章主要介紹了JAVA實(shí)現(xiàn)將磁盤(pán)中所有空文件夾進(jìn)行刪除的代碼,需要的朋友可以參考下2017-06-06
聊聊Spring?Cloud?Gateway過(guò)濾器精確控制異常返回問(wèn)題
這篇文章主要介紹了Spring?Cloud?Gateway過(guò)濾器精確控制異常返回問(wèn)題,本篇任務(wù)就是分析上述現(xiàn)象的原因,通過(guò)閱讀源碼搞清楚返回碼和響應(yīng)body生成的具體邏輯,需要的朋友可以參考下2021-11-11

