多線程同享數(shù)據(jù)(多個(gè)線程共同拜訪相同的數(shù)據(jù)),需求進(jìn)行數(shù)據(jù)同步,保證同一數(shù)據(jù)、同一時(shí)間只能被一個(gè)線程拜訪。
運(yùn)用同步是為了避免多個(gè)線程同一時(shí)間對(duì)同一數(shù)據(jù)進(jìn)行讀寫,假如對(duì)同一數(shù)據(jù)數(shù)據(jù)都只進(jìn)行讀操作、不進(jìn)行修正,則不用運(yùn)用同步。
以售票為例不運(yùn)用同步
publicclassSaleTicketThreadextendsThread{privatestaticintticket=100;//票數(shù),static@Overridepublicvoidrun(){while(ticket>0){
System.out.println(“售出第”+(100-ticket+1)+”個(gè)座位”);
ticket–;
}
}
}
publicclassSaleTicket{publicstaticvoidmain(String[]args){
SaleTicketThreadthread1=newSaleTicketThread();
thread1.start();
SaleTicketThreadthread2=newSaleTicketThread();
thread2.start();
SaleTicketThreadthread3=newSaleTicketThread();
thread3.start();
}
}
啟動(dòng)三個(gè)線程來(lái)售票,這3個(gè)線程都要拜訪同一個(gè)數(shù)據(jù)SaleTicketThread.ticket剩下票數(shù)
很簡(jiǎn)單出問(wèn)題
三種常見(jiàn)的同步辦法
同步辦法默認(rèn)用當(dāng)時(shí)目標(biāo)(this)或許當(dāng)時(shí)類的class目標(biāo)作為鎖,會(huì)給整個(gè)辦法都加鎖
同步代碼塊能夠選擇以什么作為鎖,能夠只同步會(huì)發(fā)生同步問(wèn)題的部分代碼而不是整個(gè)辦法,比同步辦法愈加細(xì)粒度
ReentrantLock以ReentrantLock目標(biāo)作為鎖,能夠只給部分代碼加鎖,比同步辦法愈加細(xì)粒度
1、同步辦法
publicclassSaleTicketThreadextendsThread{privatestaticintticket=100;//票數(shù),staticprotectedstaticsynchronizedvoidsaleTicket(){//用synchronized潤(rùn)飾辦法while(ticket>0){
System.out.println(“售出第”+(100-ticket+1)+”個(gè)座位”);
ticket–;
}
}
@Overridepublicvoidrun(){
saleTicket();
}
}
假如辦法沒(méi)有運(yùn)用static潤(rùn)飾,是實(shí)例辦法,默認(rèn)以this(當(dāng)時(shí)目標(biāo))作為鎖,假如此線程類有多個(gè)實(shí)例(多條線程),這些線程運(yùn)用的鎖不是同一個(gè)目標(biāo),起不到同步的效果。
假如辦法是靜態(tài)辦法,默認(rèn)以當(dāng)時(shí)類的class目標(biāo)作為鎖,假如此線程類有多個(gè)實(shí)例(多條線程),這些線程運(yùn)用的鎖是同一個(gè)目標(biāo),實(shí)現(xiàn)了同步,顯然應(yīng)該運(yùn)用static。
同步辦法有一個(gè)很大的問(wèn)題:只效果于當(dāng)時(shí)線程類,比如查詢、售票2個(gè)線程類都要運(yùn)用剩下票數(shù)這個(gè)同享數(shù)據(jù),都運(yùn)用同步辦法,鎖目標(biāo)不同,這2個(gè)線程類之間并沒(méi)有同步。
所以同步辦法一般用于此同享數(shù)據(jù)只效果于一個(gè)線程類的多個(gè)實(shí)例。
鎖的規(guī)模是固定(整個(gè)辦法),不能修正,不靈活;運(yùn)用狀況還有約束,有點(diǎn)雞肋。
相比之下,同步代碼塊、ReentrantLock的運(yùn)用不受約束,強(qiáng)大多了。
2、同步代碼塊
publicclassSaleTicketThreadextendsThread{privatestaticIntegerticket=100;//票數(shù),static@Overridepublicvoidrun(){synchronized(ticket){//鎖要是Object類型while(ticket>0){
System.out.println(“售出第”+(100-ticket+1)+”個(gè)座位”);
ticket–;
}}}
}
同步代碼塊能夠自己決議要運(yùn)用的鎖目標(biāo),能夠直接把同享數(shù)據(jù)作為鎖,也能夠新建一個(gè)Object目標(biāo)作為鎖。
要注意2點(diǎn):
1、鎖要是Object類型,int、float、char等根本類型沒(méi)有承繼Object,不能作為鎖,要運(yùn)用對(duì)應(yīng)的包裝類型。String承繼了Object,能夠作為鎖。
2、拜訪這一同享數(shù)據(jù)的線程,運(yùn)用的鎖目標(biāo)要相同(目標(biāo)地址要相同)。
3、ReentrantLock
publicclassSaleTicketThreadextendsThread{privatestaticIntegerticket=100;//票數(shù),staticprivatefinalstaticReentrantLocklock=newReentrantLock();//鎖目標(biāo),finalstatic潤(rùn)飾,@Overridepublicvoidrun(){lock.lock();//加鎖while(ticket>0){
System.out.println(“售出第”+(100-ticket+1)+”個(gè)座位”);
ticket–;
}lock.unlock();//開(kāi)釋鎖}
}
以ReentrantLock目標(biāo)作為鎖,注意一切要運(yùn)用此同享數(shù)據(jù)的線程運(yùn)用的應(yīng)該是同一個(gè)ReentrantLock目標(biāo)(要是同一個(gè)鎖目標(biāo))。
其實(shí)和同步代碼塊差不多,lock()標(biāo)志同步代碼塊開(kāi)始,unlock()標(biāo)志同步代碼塊完畢。
可能發(fā)生反常的狀況:
publicclassXxxThreadextendsThread{privatefinalstaticReentrantLocklock=newReentrantLock();//鎖目標(biāo),finalstatic潤(rùn)飾@Overridepublicvoidrun(){//…lock.lock();//加鎖try{//……//放在try中}catch(){//…..}finally{
lock.unlock();//在finally中開(kāi)釋鎖,避免發(fā)生反常后鎖沒(méi)有開(kāi)釋,其它線程一直等候}//…..}
}
說(shuō)明
能夠把同享數(shù)據(jù)、鎖能夠放在某個(gè)線程中作為靜態(tài)變量,
假如要在不同的線程類中運(yùn)用,比如在查詢、售票2個(gè)線程類中都要運(yùn)用剩下票數(shù)這個(gè)成員變量,那就聲明為publicstatic,暴露出來(lái);
假如只在一個(gè)線程類中運(yùn)用(此線程類的多個(gè)實(shí)例同享此數(shù)據(jù)),設(shè)置成privatestatic即可。
也能夠把同享數(shù)據(jù)、鎖放在父線程(開(kāi)啟它們的線程)中,在線程類的結(jié)構(gòu)函數(shù)中傳入同享數(shù)據(jù)、鎖目標(biāo)。
總之,要一切拜訪這個(gè)同享數(shù)據(jù)的線程都能夠拜訪到同享數(shù)據(jù)、鎖。
廣州天河區(qū)珠江新城富力盈力大廈北塔2706
020-38013166(網(wǎng)站咨詢專線)
400-001-5281 (售后服務(wù)熱線)
深圳市坂田十二橡樹(shù)莊園F1-7棟
Site/ http://www.szciya.com
E-mail/ itciya@vip.163.com
品牌服務(wù)專線:400-001-5281
長(zhǎng)沙市天心區(qū)芙蓉中路三段398號(hào)新時(shí)空大廈5樓
聯(lián)系電話/ (+86 0731)88282200
品牌服務(wù)專線/ 400-966-8830
旗下運(yùn)營(yíng)網(wǎng)站:
Copyright ? 2016 廣州思洋文化傳播有限公司,保留所有權(quán)利。 粵ICP備09033321號(hào)