在安全性與活躍性之間一般存在着某種制衡,咱們使用加鎖機制來確保線程安全,但若是過分地使用加鎖,則可能致使「鎖順序死鎖」。一樣,咱們使用線程池和信號量來限制對資源的使用,但這些被限制的行爲可能會致使資源死鎖。安全
鎖順序死鎖:兩個線程試圖以不一樣的順序來得到相同的鎖,若是按照相同的順序來請求鎖,那麼就不會出現循環的加鎖依賴性,所以也就不會產生死鎖。 在制定鎖的順序時,可使用System.identityHashCode方法,該方法返回有Object.hashCode返回的值,經過比較大小等方法定義鎖的順序。在某些狀況下,兩個對象可能擁有相同的散列值,此時必須經過某種方法來決定鎖的順序,而這可能會從新引入死鎖,爲了不這種狀況,可使用「加時賽」鎖,在得到兩個對象的鎖以前,首先得到這個加時賽鎖,從而保證每次只有一個線程以未知的順序得到這兩個鎖。併發
在協做對象之間發生的死鎖 若是在持有鎖的狀況下調用某個外部方法,那麼就須要警戒在協做對象之間發生死鎖。 若是在持有鎖時調用某個外部方法,那麼將出現活躍性問題,在這個外部方法中可能會得到其餘鎖(這可能會產生死鎖),或者阻塞時間過長,致使其餘線程沒法及時得到當前被持有的鎖。ide
開放調用 若是在調用某個方法時不須要持有鎖,那麼這種調用被稱爲開放調用。 在程序中應儘可能使用開放調用。與那些在持有鎖時調用外部方法的程序相比,更易於對依賴於開放調用的程序進行死鎖分析。線程
資源死鎖設計
引起飢餓的最多見資源就是CPU時鐘週期,若是在Java應用程序中對線程的優先級使用不當,或者在持有鎖時執行一些沒法結束的結構(例如無限循環,或者無限制地等待某個資源),那麼也可能致使飢餓,由於其餘須要這個鎖的線程將沒法獲得它。線程優先級並非一種直觀的機制,而經過修改線程優先級所帶來的效果一般也不明顯。當提升某個線程的優先級時,可能不會起到任何做用,或者也可能使得某個線程的調度優先級高於其餘線程,從而致使飢餓。code
一般,咱們儘可能不要改變線程的優先級。只要改變了線程的優先級,程序的行爲就將與平臺相關,而且會致使發生飢餓問題的風險。 Thread.yield以及Thread.sleep的語義都是UB,JVM既能夠將他們實現爲空操做,也能夠將它們視爲線程調度的參考。
活鎖是另外一種形式的活躍性問題,該問題不會致使線程阻塞,但也不能繼續執行。由於線程將不斷重複執行相同的操做,並且總會失敗。 活鎖一般發生在處理事務消息的應用程序中:若是不能成功處理某個消息,那麼消息處理機制將回滾整個事務,並將它從新放到隊列的開頭。當多個相互協做的線程都對彼此進行響應從而修改各自的狀態,並使得任何一個線程沒法繼續執行時,就發生了活鎖,在併發應用程序中,經過等待隨機長度的時間和回退能夠有效避免活鎖的發生。對象