死鎖相關問題

什麼是死鎖

兩個或兩個以上的進程在執行過程中,因爭奪資源而造成的一種

相互等待的現象,若無外力作用,他們都將無法推進下去,陷入死循環

產生死鎖的必要條件

  1. 互斥. 一個資源每次只能被一個線程使用
  2. 禁止搶佔. 線程已獲得的資源, 在未使用完之前, 不能強行剝奪
  3. 持有和等待. 一個線程因請求資源而阻塞時, 對已獲得的資源保持不放
  4. 循環等待. 系列進程互相持有其他進程所需要的資源, 造成互相等待的局面

死鎖的預防

上面介紹了死鎖的四個必要條件, 只要破壞了四個必要條件中的任意一個條件, 死鎖就不會發生了.

1.打破互斥條件

就是允許進程同時訪問某些資源. 但是, 有的資源不允許被同時訪問, 這是由資源本身的屬性決定的. 所以, 這種辦法並無使用價值

2.打破禁止搶佔

就是允許進程強行從佔有者那裡奪取資源. 當一個進程已佔有了某些資源, 有申請新的資源, 但不能立即被滿足時, 必須釋放所佔有的全部資源, 以後再重新申請. 這種預防思索的方法實現起來困難, 會降低系統性能.

3.打破持有和等待狀態

可以實行資源預先分配策略. 即進程在運行前一次性地向系統申請它所需要的全部資源. 如果某個進程所需的全部資源得不到滿足, 則不分配任何資源, 此進程暫不運行. 只有當系統能夠滿足當前進程的全部資源需求時, 才一次性地將所申請的資源全部分配給該進程. 由於運行的進程已佔有了它所需的全部資源, 所以不會發生佔有資源又申請資源的現象, 因此不會發生死鎖. 但是, 這種策略有如下缺點:

  1. 許多情況下, 一個進程在執行之前並不可能知道它所需要的全部資源. 這是由於進程執行時是動態的, 不可預測的.
  2. 資源利用率低. 無論所分資源何時用到, 一個進程要佔有全部資源後才能執行. 即使有些資源最後才被該進程用到一次, 但該進程在生存期一直佔有它, 造成長期佔著不用的狀況. 顯然是一種極大的資源浪費.
  3. 降低了進程的併發性. 因為資源有限, 又加上存在浪費, 能分配到需要的全部資源的進程個數必然少了

4.打破循環等待

實行資源有序分配策略. 即將資源事先編號, 按號分配, 進程對資源的請求必須按資源序號遞增的舒徐提出. 這樣就不會差生環路, 從而預防了死鎖. 這種策略與前面的策略相比, 資源的利用率和系統吞吐量都有很大提高, 但是也存在以下缺點:

  1. 限制了進程對資源的請求, 同時給系統中所有資源編號也是件困難事, 增加了系統開銷.
  2. 為了遵循按編號申請的次序, 暫不使用的資源也需要提前申請, 增加了進程對資源的佔用時間.

Java中死鎖的避免

1.加鎖順序

當多個線程需要相同的一些鎖, 但是按照不同的順序加鎖, 死鎖就很容易發生.

如果能確保所有的縣城都是按照相同的順序獲得鎖, 那麼死鎖就不會發生了.

2.加鎖時限

可以避免死鎖的方法是在嘗試獲取鎖的時候加一個超時時間, 線程可以在獲取鎖超時以後主動釋放之前已經獲得的所有的鎖. 通過這種方式, 也可以很有效的避免死鎖

使用Lock接口的 tryLock(long, TimeUnit) 方法, 當獲取鎖超時時主動釋放之前已經獲得的所有鎖.

4.通過信號量控制

信號量可以控制資源能被多少線程訪問, 指定只能被一個線程訪問時, 就做到了類似鎖的操作.

Java 中的 Semaphore 類可以做到信號量控制, 通過 tryAcquire(int, long, TimeUnit) 方法獲取信號量許可, 超時則為其他線程佔用, 釋放所有已獲取的許可. 代碼如下:

死鎖相關問題

Java定位死鎖

1.使用 JConsole 命令

通過JDK帶的 java監視和管理控制檯 工具, 可以查看java進程運行情況

在cmd運行 jconsole 打開

2.使用 jstack 命令

先通過 jps 命令查看 java進程的id

然後通過 jstack id 查看該進程的堆棧情況及錯誤信息


分享到:


相關文章: