死锁处理【转】
轉(zhuǎn)自:lemonGuo
死鎖出現(xiàn)的場景
根據(jù)以上分析總結(jié)一下最壞的情況:
- synchronized(from):別的線程在等待from對象;
- synchronized(to):別的線程已經(jīng)鎖住了to對象;
因此,可能出現(xiàn)死鎖的情況就是: transfer(a,b,100) 和 transfer(b,a,100)同時進行,這是對雙方都很不利的情況:左邊的搶走了a的鎖,右邊的搶走了b的鎖。
形成死鎖的條件
- 互斥等待:說白了也就是要在有鎖的情況。
- hold and wait:拿到一個鎖去等待另一個鎖的狀態(tài),其實鎖是很珍貴的資源,最好得到鎖后盡快處理完畢將其釋放。
- 循環(huán)等待:更槽糕的情況:例如線程1獲得鎖A在等待鎖B,而線程2獲取鎖B在等待鎖A。
- 無法剝奪的等待:在出現(xiàn)循環(huán)等待情況后,有的鎖會出現(xiàn)超時后自動釋放,但是若是一直等待,則必定死鎖。
防止死鎖的辦法
若要避免死鎖,根據(jù)以上四個產(chǎn)生死鎖的原因,逐一破解即可:
-
破除互斥等待:不可!鎖是保證線程安全的基本方法,無法實現(xiàn)。
-
破除hold and wait:可以!最關(guān)鍵的一步,就是一次性獲取所有資源。例子中的from、to對象是分成兩步獲取的,從而會形成hold and wait情況,但是通常不允許同時鎖兩個對象,因此需要對代碼做比較大的修改:
- 暴露一個鎖名為getAmountLock,它是針對Amount的,from、to對象都可以getAmountLock,鎖的時候可以帶上一個短的超時,先鎖住from再鎖住to,當to鎖不住的時候,把from鎖放掉,過段時間再嘗試。
- 或者在這兩行的外面加一個全局的鎖,保證可以同時拿到這兩個鎖,拿到這兩個鎖之后再將全局的鎖釋放掉。但是需要結(jié)合實際,銀行系統(tǒng)中Amount的量很大,全局鎖未必好,第一個方案較好。
-
破除循環(huán)等待:可以!按順序獲取資源。
- 讓例子中的Amount之間有序,不要先synchronized對象from,再synchronized對象to,銀行中AmountID肯定是惟一值,所以定制一個規(guī)則先處理較小值,這樣即使同時互相轉(zhuǎn)賬,也不會出現(xiàn)死鎖情況。
-
破除無法剝奪的等待:可以!加入超時。
- 設(shè)置超時時間5秒或者其它,但此方法并不理想,因為超時需要時間等待,耗時長,用戶體驗差。
總結(jié)
根據(jù)以上的分析,也許你認為第四種加入超時措施相對簡單實現(xiàn),但是如此一來不能使用synchronized,還要暴露一個鎖;第二種?from.getAmountLock()方法實現(xiàn)較復(fù)雜。
因此,第二種解決方法較好,即破除循環(huán)等待—–按順序獲取資源,出現(xiàn)并發(fā)時根據(jù)AmountID值先處理值較小的用戶,但是這并不是最好的解決方法,因為此解決方法重點為按順序獲取資源,而銀行賬戶中的ID順序性是我假設(shè)出來的,并非實際。
所以,最理想的解決方法還是破除hold and wait,就是一次性獲取所有資源!但是通常不允許同時鎖兩個對象,所以還是先鎖住A再鎖住B,當B鎖不住的時候,把A鎖放掉,過段時間再嘗試。
完美的解決辦法不存在!所以只能根據(jù)實際問題具體分析,選擇一個折中的辦法實現(xiàn)
轉(zhuǎn)載于:https://www.cnblogs.com/demian/p/9603849.html
《新程序員》:云原生和全面數(shù)字化實踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
- 上一篇: nginx高性能WEB服务器系列之九--
- 下一篇: 数字变化滚动到指定数字的文字特效