- 資訊首頁(yè) > 開(kāi)發(fā)技術(shù) >
- Java中線(xiàn)程安全問(wèn)題
多線(xiàn)程的執行環(huán)境中,程序的執行結果和預期的結果不符合,這就稱(chēng)為發(fā)生了線(xiàn)程不安全現象
大致分為以下5種情況:
(1)CPU搶占執行 (無(wú)法解決);
(2)非原子性 ;
(3)編譯器優(yōu)化(指令重排) 編譯器優(yōu)化在單線(xiàn)程下執行沒(méi)問(wèn)題,多線(xiàn)程下優(yōu)化會(huì )發(fā)生混亂;
(4)內存的不可見(jiàn)性 ;(volatile輕量級解決)
(5)多個(gè)線(xiàn)程修改了同一個(gè)變量。(方案:讓線(xiàn)程操作自己的變量可以解決該問(wèn)題,但業(yè)務(wù)場(chǎng)景發(fā)生變化,修改難度變大,通用性不高)
volatile的出現可以解決上圖所展現的內存不可見(jiàn)問(wèn)題以及禁止指令重排
實(shí)現原理:工作內存中的變量操作結束后,強制刪除線(xiàn)程工作內存中的變量,起到內存可見(jiàn)注意事項:volatile不能解決原子性問(wèn)題。volatile可以解決線(xiàn)程不安全問(wèn)題是錯誤的(說(shuō)法不夠嚴謹)
下面兩種方案通過(guò)對關(guān)鍵代碼加鎖,讓cpu排隊執行,鎖操作的步驟為:
1)嘗試獲取鎖,如果拿到則加鎖,否則排隊等待獲取鎖 2)釋放鎖操作
①synchronized進(jìn)行自動(dòng)加鎖和釋放鎖,是Jvm層面的解決方案
synchronized使用舉例:使用兩個(gè)線(xiàn)程對變量count進(jìn)行一次++ 和 一次- -
沒(méi)有使用synchronized上鎖之前,由于非原子問(wèn)題,兩個(gè)線(xiàn)程進(jìn)行++和- -出現線(xiàn)程不安全問(wèn)題,通過(guò)synchronized關(guān)鍵字的使用,解決了非原子問(wèn)題,代碼運行實(shí)際結果和預期結果一致,保證了線(xiàn)程安全。
②synchronized實(shí)現原理:
1.基于操作系統而言,通過(guò)互斥鎖mutex實(shí)現
mutex結構信息:
2.從Jvm層面來(lái)看,實(shí)現了一個(gè)監視器鎖的加鎖和釋放鎖過(guò)程。
3.從Java語(yǔ)言本身來(lái)看,存在一個(gè)互斥鎖mutex對象,鎖存在于對象的對象頭中,對象頭中的“偏向線(xiàn)程ID”,表明該鎖被該線(xiàn)程占有,釋放鎖后,偏向線(xiàn)程ID消失。
Owner代表鎖的擁有者,為null時(shí)表示鎖未使用;Nest表示鎖的使用次數,為0表示沒(méi)有被使用;此外鎖可以嵌套使用,不會(huì )發(fā)生死鎖情況。
③synchronized鎖升級過(guò)程:
沒(méi)有線(xiàn)程訪(fǎng)問(wèn)時(shí)處于無(wú)鎖狀態(tài) >> 第一個(gè)線(xiàn)程訪(fǎng)問(wèn)時(shí),由無(wú)鎖狀態(tài)轉為偏向鎖 >> 輕量級鎖(其他線(xiàn)程嘗試獲取鎖,鎖處于自旋狀態(tài)) >> 重量級鎖(把沒(méi)有拿到鎖的線(xiàn)程放到等待隊列里面)
3.Lock手動(dòng)上鎖
Lock需要程序員自己手動(dòng)上鎖手動(dòng)釋放鎖;Lock是一個(gè)interface;創(chuàng )建鎖時(shí)可以通過(guò)Lock的實(shí)現類(lèi)ReentrantLock()完成:Lock lock = new ReentrantLock();加鎖操作lock.lock(),釋放鎖操作lock.unlock()
使用Lock需要注意的問(wèn)題:
一定要把加鎖操作lock()放在try/finally外面如果把lock()放在try中會(huì )導致兩個(gè)問(wèn)題發(fā)生:
(1)try中代碼出現異常,此時(shí)就會(huì )執行finally中釋放鎖的操作,如果try還沒(méi)有加鎖就去釋放鎖,勢必是不行的。
(2)try中出現異常后,執行finally中釋放鎖操作,線(xiàn)程狀態(tài)異常會(huì )將try中業(yè)務(wù)異常覆蓋掉,增加了排除錯誤的成本。
將lock()放在try中第一句可以解決這個(gè)問(wèn)題
對比發(fā)現,這樣做業(yè)務(wù)異常是不會(huì )被線(xiàn)程的狀態(tài)異常覆蓋的,方便了排查錯誤?。?!
公平鎖線(xiàn)程按順序執行;非公平鎖沒(méi)有順序,執行效率更高;Java中默認鎖策略為非公平鎖機制synchronized鎖機制:采用非公平鎖機制Lock鎖機制:默認采用非公平鎖機制,但是可以顯示地聲明為公平鎖,比如在創(chuàng )建鎖對象時(shí),在構造方法中傳true:Lock lock = new ReentrantLock(true)
volatile可以解決內存不可見(jiàn)問(wèn)題以及禁止指令重排序,但是不能解決非原子性問(wèn)題;
synchronized可以解決大部分線(xiàn)程的非安全問(wèn)題,保證關(guān)鍵代碼排隊執行,無(wú)論何時(shí)鎖只被一個(gè)線(xiàn)程擁有,可解決非原子性問(wèn)題
1.synchronized自動(dòng)加鎖和釋放鎖,而Lock需要手動(dòng)加鎖和釋放鎖;
2.synchronized是Jvm層面的實(shí)現,Lock是Java語(yǔ)言層面的實(shí)現;
3.適用范圍不同:synchronized可以修飾代碼塊(對任意對象加鎖)、修飾靜態(tài)方法(對當前的類(lèi)進(jìn)行加鎖)、修飾普通的方法(對當前的實(shí)例對象進(jìn)行加鎖);而Lock只能修飾代碼塊;
4.synchronized只有非公平鎖策略;Lock默認采用非公平鎖機制,但可以顯示聲明為公平鎖;
5.Lock的靈活性更高一些(比如:tryLock)
到此這篇關(guān)于Java中線(xiàn)程安全問(wèn)題的文章就介紹到這了,更多相關(guān)Java線(xiàn)程安全內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自互聯(lián)網(wǎng)轉載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權請聯(lián)系QQ:712375056 進(jìn)行舉報,并提供相關(guān)證據,一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容。
Copyright ? 2009-2021 56dr.com. All Rights Reserved. 特網(wǎng)科技 特網(wǎng)云 版權所有 珠海市特網(wǎng)科技有限公司 粵ICP備16109289號
域名注冊服務(wù)機構:阿里云計算有限公司(萬(wàn)網(wǎng)) 域名服務(wù)機構:煙臺帝思普網(wǎng)絡(luò )科技有限公司(DNSPod) CDN服務(wù):阿里云計算有限公司 中國互聯(lián)網(wǎng)舉報中心 增值電信業(yè)務(wù)經(jīng)營(yíng)許可證B2
建議您使用Chrome、Firefox、Edge、IE10及以上版本和360等主流瀏覽器瀏覽本網(wǎng)站