千鋒(feng)教育-做有(you)情懷、有(you)良心(xin)、有(you)品(pin)質的職業教育機構
使用多線程(cheng)主要會帶來以下幾個(ge)問(wen)題(ti):
一、線程安全問題
線(xian)(xian)程(cheng)安全(quan)(quan)問題(ti)指的(de)(de)是在(zai)某(mou)一(yi)線(xian)(xian)程(cheng)從開始訪(fang)(fang)問到結束訪(fang)(fang)問某(mou)一(yi)數(shu)(shu)據(ju)期(qi)間,該(gai)數(shu)(shu)據(ju)被(bei)其(qi)他的(de)(de)線(xian)(xian)程(cheng)所修改,那么(me)對于當前(qian)線(xian)(xian)程(cheng)而言(yan),該(gai)線(xian)(xian)程(cheng)就發生(sheng)了(le)線(xian)(xian)程(cheng)安全(quan)(quan)問題(ti),表(biao)現形式為(wei)數(shu)(shu)據(ju)的(de)(de)缺失(shi),數(shu)(shu)據(ju)不一(yi)致等。
線程安全問題發生(sheng)的條件:
1)多線程環境下,即存(cun)(cun)在(zai)(zai)包括自己在(zai)(zai)內存(cun)(cun)在(zai)(zai)有多個(ge)線程。
2)多(duo)線程(cheng)環境下存在共享資源,且多(duo)線程(cheng)操作該共享資源。
3)多個線程必須對該共享資源有(you)非(fei)原子性操作。
線(xian)程安全問題的解(jie)決(jue)思路:
1)盡量不使(shi)用共享變(bian)量,將不必要的共享變(bian)量變(bian)成局部(bu)變(bian)量來使(shi)用。
2)使(shi)用(yong)synchronized關鍵(jian)字(zi)同(tong)步代(dai)碼塊,或者使(shi)用(yong)jdk包中提供的Lock為操(cao)作(zuo)進行(xing)加(jia)鎖。
3)使用ThreadLocal為每一(yi)個(ge)線(xian)程建立一(yi)個(ge)變量的副本,各個(ge)線(xian)程間獨立操作(zuo),互不影(ying)響(xiang)。
二、性能問題
線程(cheng)(cheng)(cheng)的(de)(de)(de)(de)生命周期(qi)開銷是非常大(da)的(de)(de)(de)(de),一個線程(cheng)(cheng)(cheng)的(de)(de)(de)(de)創建到銷毀都會占用大(da)量的(de)(de)(de)(de)內存(cun)。同時如果不(bu)合理的(de)(de)(de)(de)創建了多(duo)個線程(cheng)(cheng)(cheng),cup的(de)(de)(de)(de)處理器(qi)數量小于(yu)了線程(cheng)(cheng)(cheng)數量,那么(me)將(jiang)會有很(hen)多(duo)的(de)(de)(de)(de)線程(cheng)(cheng)(cheng)被閑置,閑置的(de)(de)(de)(de)線程(cheng)(cheng)(cheng)將(jiang)會占用大(da)量的(de)(de)(de)(de)內存(cun),為(wei)垃圾回(hui)收(shou)帶(dai)來很(hen)大(da)壓力,同時cup在分(fen)配線程(cheng)(cheng)(cheng)時還會消耗其性能。
解決思路:
利用線(xian)(xian)程(cheng)池(chi)(chi),模擬一(yi)個(ge)(ge)池(chi)(chi),預先創(chuang)建有(you)限合理個(ge)(ge)數的(de)(de)線(xian)(xian)程(cheng)放(fang)入(ru)池(chi)(chi)中,當需(xu)要執(zhi)(zhi)行任(ren)(ren)務(wu)(wu)時從池(chi)(chi)中取出空閑的(de)(de)先去執(zhi)(zhi)行任(ren)(ren)務(wu)(wu),執(zhi)(zhi)行完成后將線(xian)(xian)程(cheng)歸還到池(chi)(chi)中,這(zhe)樣(yang)就(jiu)減少(shao)了線(xian)(xian)程(cheng)的(de)(de)頻(pin)繁(fan)創(chuang)建和銷毀,節省(sheng)內存(cun)開銷和減小(xiao)了垃(la)圾(ji)回(hui)收的(de)(de)壓力。同時因(yin)為任(ren)(ren)務(wu)(wu)到來(lai)時本(ben)身線(xian)(xian)程(cheng)已(yi)經(jing)存(cun)在,減少(shao)了創(chuang)建線(xian)(xian)程(cheng)時間,提高了執(zhi)(zhi)行效率,而(er)且合理的(de)(de)創(chuang)建線(xian)(xian)程(cheng)池(chi)(chi)數量還會使各個(ge)(ge)線(xian)(xian)程(cheng)都處于忙碌狀態,提高任(ren)(ren)務(wu)(wu)執(zhi)(zhi)行效率,線(xian)(xian)程(cheng)池(chi)(chi)還提供了拒絕策(ce)略,當任(ren)(ren)務(wu)(wu)數量到達(da)某一(yi)臨界區時,線(xian)(xian)程(cheng)池(chi)(chi)將拒絕任(ren)(ren)務(wu)(wu)的(de)(de)進入(ru),保持現(xian)有(you)任(ren)(ren)務(wu)(wu)的(de)(de)順利執(zhi)(zhi)行,減少(shao)池(chi)(chi)的(de)(de)壓力。
三、活躍性問題
1)死鎖
假(jia)如線程 A 持(chi)有資源(yuan) 2,線程 B 持(chi)有資源(yuan) 1,他們同(tong)時都想申(shen)請對方的資源(yuan),所以這兩(liang)個(ge)線程就會互(hu)相等(deng)待(dai)而進入死鎖狀(zhuang)態。多個(ge)線程環形占用(yong)資源(yuan)也是一樣的會產生死鎖問題。
解決方法:
- 避免一個(ge)線程(cheng)同(tong)時獲取多個(ge)鎖
- 避免一(yi)個(ge)線程在(zai)鎖內同時占(zhan)用多個(ge)資(zi)源(yuan),盡量保(bao)證每個(ge)鎖只占(zhan)用一(yi)個(ge)資(zi)源(yuan)。
- 嘗試使(shi)(shi)用(yong)(yong)定時鎖(suo)(suo),使(shi)(shi)用(yong)(yong) lock.tryLock(timeout) 來代(dai)替使(shi)(shi)用(yong)(yong)內部鎖(suo)(suo)機制。 想要(yao)避(bi)免死鎖(suo)(suo),可以使(shi)(shi)用(yong)(yong)無鎖(suo)(suo)函數(cas)或者使(shi)(shi)用(yong)(yong)重入鎖(suo)(suo)(ReentrantLock),通過(guo)重入鎖(suo)(suo)使(shi)(shi)線程中斷或限時等待可以有效的規避(bi)死鎖(suo)(suo)問題。
2)饑餓
饑餓指的是某(mou)(mou)一(yi)(yi)(yi)線(xian)程(cheng)或多個(ge)線(xian)程(cheng)因(yin)(yin)為某(mou)(mou)些原因(yin)(yin)一(yi)(yi)(yi)直(zhi)獲取(qu)不(bu)到資源,導(dao)致程(cheng)序一(yi)(yi)(yi)直(zhi)無法執行(xing)。如某(mou)(mou)一(yi)(yi)(yi)線(xian)程(cheng)優(you)先級太低導(dao)致一(yi)(yi)(yi)直(zhi)分配不(bu)到資源,或者是某(mou)(mou)一(yi)(yi)(yi)線(xian)程(cheng)一(yi)(yi)(yi)直(zhi)占著某(mou)(mou)種資源不(bu)放,導(dao)致該(gai)線(xian)程(cheng)無法執行(xing)等。
解決方法:
與死鎖相(xiang)比,饑餓(e)現象還是有可(ke)能在一(yi)段時間之(zhi)后恢(hui)復執行的。可(ke)以設置合適的線(xian)程優(you)先(xian)級來盡量(liang)避免饑餓(e)的產生(sheng)。
3)活鎖
活(huo)鎖體現了一種(zhong)謙讓(rang)的(de)美(mei)德,每(mei)個(ge)線程(cheng)都(dou)想把資(zi)源讓(rang)給(gei)對方,但(dan)是(shi)(shi)由(you)于機器(qi)“智商”不夠,可能會產生一直將(jiang)資(zi)源讓(rang)來讓(rang)去,導致(zhi)資(zi)源在兩個(ge)線程(cheng)間跳(tiao)動(dong)而無法(fa)使(shi)某一線程(cheng)真正的(de)到資(zi)源并執行,這(zhe)就(jiu)是(shi)(shi)活(huo)鎖的(de)問題(ti)。
四、阻塞
阻(zu)塞(sai)是(shi)用(yong)來形容多線程(cheng)(cheng)(cheng)(cheng)的(de)問題,幾個(ge)(ge)線程(cheng)(cheng)(cheng)(cheng)之間共享臨(lin)界區(qu)資源,那么(me)當一(yi)(yi)(yi)(yi)個(ge)(ge)線程(cheng)(cheng)(cheng)(cheng)占用(yong)了(le)臨(lin)界區(qu)資源后(hou),所(suo)有需要使用(yong)該(gai)資源的(de)線程(cheng)(cheng)(cheng)(cheng)都(dou)(dou)需要進入該(gai)臨(lin)界區(qu)等待(dai),等待(dai)會導致線程(cheng)(cheng)(cheng)(cheng)掛起,一(yi)(yi)(yi)(yi)直不(bu)能(neng)工(gong)作,這種情況就(jiu)是(shi)阻(zu)塞(sai),如(ru)果某(mou)一(yi)(yi)(yi)(yi)線程(cheng)(cheng)(cheng)(cheng)一(yi)(yi)(yi)(yi)直都(dou)(dou)不(bu)釋放(fang)資源,將(jiang)會導致其他(ta)所(suo)有等待(dai)在這個(ge)(ge)臨(lin)界區(qu)的(de)線程(cheng)(cheng)(cheng)(cheng)都(dou)(dou)不(bu)能(neng)工(gong)作。
當我們使用(yong)synchronized或重入鎖(suo)(suo)時,我們得(de)到(dao)的(de)就是阻塞線(xian)程,如論是synchronized或者重入鎖(suo)(suo),都(dou)會在試圖執行代碼前,得(de)到(dao)臨(lin)界區的(de)鎖(suo)(suo),如果得(de)不到(dao)鎖(suo)(suo),線(xian)程將會被掛起等待,知道(dao)其(qi)他線(xian)程執行完成并釋放鎖(suo)(suo)且拿(na)到(dao)鎖(suo)(suo)為(wei)止(zhi)。
解決方法:
可以通過減少鎖(suo)持(chi)有(you)時間,讀寫鎖(suo)分離(li),減小(xiao)鎖(suo)的粒度,鎖(suo)分離(li),鎖(suo)粗化等方(fang)式(shi)來優化鎖(suo)的性能。
臨(lin)界區(qu): 臨(lin)界區(qu)是用(yong)來表示一(yi)種公共的資源(yuan)(yuan)(共享數據(ju)),它(ta)可(ke)以被(bei)多個(ge)(ge)線(xian)程(cheng)(cheng)使用(yong),但(dan)是在(zai)每次只能有一(yi)個(ge)(ge)線(xian)程(cheng)(cheng)能夠使用(yong)它(ta),當臨(lin)界區(qu)資源(yuan)(yuan)正在(zai)被(bei)一(yi)個(ge)(ge)線(xian)程(cheng)(cheng)使用(yong)時,其他的線(xian)程(cheng)(cheng)就只能等待(dai)當前線(xian)程(cheng)(cheng)執(zhi)行完之后才能使用(yong)該臨(lin)界區(qu)資源(yuan)(yuan)。
比(bi)如辦(ban)公室辦(ban)公室里(li)有一(yi)支(zhi)筆(bi),它一(yi)次只(zhi)能被一(yi)個人使用(yong),假如它正(zheng)在被甲(jia)使用(yong)時,其(qi)他想要使用(yong)這(zhe)支(zhi)筆(bi)的人只(zhi)能等(deng)甲(jia)使用(yong)完這(zhe)支(zhi)筆(bi)之后才(cai)能允許另一(yi)個人去使用(yong)。這(zhe)就是臨(lin)界區的概念。
相關推薦