死鎖處理【轉】
阿新 • • 發佈:2018-09-07
若是 狀態 net from transfer csdn tails 最好 出現
轉自:lemonGuo
死鎖出現的場景
根據以上分析總結一下最壞的情況:
- synchronized(from):別的線程在等待from對象;
- synchronized(to):別的線程已經鎖住了to對象;
因此,可能出現死鎖的情況就是: transfer(a,b,100) 和 transfer(b,a,100)同時進行,這是對雙方都很不利的情況:左邊的搶走了a的鎖,右邊的搶走了b的鎖。
形成死鎖的條件
- 互斥等待:說白了也就是要在有鎖的情況。
- hold and wait:拿到一個鎖去等待另一個鎖的狀態,其實鎖是很珍貴的資源,最好得到鎖後盡快處理完畢將其釋放。
- 循環等待:更槽糕的情況:例如線程1獲得鎖A在等待鎖B,而線程2獲取鎖B在等待鎖A。
- 無法剝奪的等待:在出現循環等待情況後,有的鎖會出現超時後自動釋放,但是若是一直等待,則必定死鎖。
防止死鎖的辦法
若要避免死鎖,根據以上四個產生死鎖的原因,逐一破解即可:
-
破除互斥等待:不可!鎖是保證線程安全的基本方法,無法實現。
-
破除hold and wait:可以!最關鍵的一步,就是一次性獲取所有資源。例子中的from、to對象是分成兩步獲取的,從而會形成hold and wait情況,但是通常不允許同時鎖兩個對象,因此需要對代碼做比較大的修改:
- 暴露一個鎖名為getAmountLock,它是針對Amount的,from、to對象都可以getAmountLock,鎖的時候可以帶上一個短的超時,先鎖住from再鎖住to,當to鎖不住的時候,把from鎖放掉,過段時間再嘗試。
- 或者在這兩行的外面加一個全局的鎖,保證可以同時拿到這兩個鎖,拿到這兩個鎖之後再將全局的鎖釋放掉。但是需要結合實際,銀行系統中Amount的量很大,全局鎖未必好,第一個方案較好。
- 暴露一個鎖名為getAmountLock,它是針對Amount的,from、to對象都可以getAmountLock,鎖的時候可以帶上一個短的超時,先鎖住from再鎖住to,當to鎖不住的時候,把from鎖放掉,過段時間再嘗試。
-
破除循環等待:可以!按順序獲取資源。
- 讓例子中的Amount之間有序,不要先synchronized對象from,再synchronized對象to,銀行中AmountID肯定是惟一值,所以定制一個規則先處理較小值,這樣即使同時互相轉賬,也不會出現死鎖情況。
-
破除無法剝奪的等待:可以!加入超時。
- 設置超時時間5秒或者其它,但此方法並不理想,因為超時需要時間等待,耗時長,用戶體驗差。
總結
根據以上的分析,也許你認為第四種加入超時措施相對簡單實現,但是如此一來不能使用synchronized,還要暴露一個鎖;第二種 from.getAmountLock()
方法實現較復雜。
因此,第二種解決方法較好,即破除循環等待—–按順序獲取資源,出現並發時根據AmountID值先處理值較小的用戶,但是這並不是最好的解決方法,因為此解決方法重點為按順序獲取資源,而銀行賬戶中的ID順序性是我假設出來的,並非實際。
所以,最理想的解決方法還是破除hold and wait,就是一次性獲取所有資源!但是通常不允許同時鎖兩個對象,所以還是先鎖住A再鎖住B,當B鎖不住的時候,把A鎖放掉,過段時間再嘗試。
完美的解決辦法不存在!所以只能根據實際問題具體分析,選擇一個折中的辦法實現
死鎖處理【轉】