五、活躍性問題
活躍性問題包括死鎖、活鎖、飢餓,最著名的就是死鎖問題了。
5.1、死鎖
5.1.1、什麼是死鎖
系統中的每乙個執行緒都持有著其他執行緒需要的資源,同時又想獲取其他執行緒已經擁有的資源,並且每個執行緒在獲取全部想要的資源之前不會釋放已經擁有的資源,那麼這種情況就稱為死鎖。
例如:當執行緒一持有a鎖,想要獲取b鎖的同時,執行緒二持有者b鎖,並且想要獲取a鎖。那麼執行緒一和執行緒二就產生了死鎖,兩個執行緒會永遠的阻塞下去。
5.1.2、死鎖**
public class deadlockdemo catch (interruptedexception e)
synchronized (lock2)
}});
thread t2 = new thread(() -> catch (interruptedexception e)
synchronized (lock1)
}});
t1.start();
t2.start();
t1.join();
t2.join();
system.out.println("執行完畢");
}}
執行結果:
t1獲取
lock1
t2獲取lock2
5.1.3、如何辨別死鎖**
(1)辨明**中所有的同步**共有幾個鎖物件,如果只有乙個,是不會產生死鎖的,如果有多個則需要小心;
(2)在同步**塊中,是否有呼叫其他方法的情況,如果有就有很大的風險。
(3)檢視這些同步**塊呼叫其他同步方法的**的獲取鎖的順序,如果多個這種呼叫的情況順序是不一樣的,那麼就有可能產生死鎖。
5.1.4、死鎖的必要條件
(1)互斥條件:乙個資源一次只能有乙個執行緒可以使用,如果有另乙個執行緒申請該資源,那麼這個執行緒進入阻塞狀態知道資源被釋放;(synchronized獨佔鎖)
(2)請求與保持條件:乙個執行緒因請求了被其他執行緒占用的資源而進入阻塞狀態時,這個執行緒對自己持有的資源不會釋放;
(3)不剝奪條件:乙個執行緒獲取了某個資源後,只能程序自己資源釋放資源,不能強行剝奪;
(4)迴圈等待條件:有一組等待執行緒 ,p0 等待的資源為 p1 占有,p1 等待的資源為 p2 占有,……,pn-1 等待的資源為 pn 占有,pn 等待的資源為 p0 占有。
這四個條件是形成死鎖的必要條件,非充分條件,即同時滿足這四個條件也不一定會產生死鎖,但是產生了死鎖,肯定是滿足了這四個條件。只有上訴四個條件之一不滿足,肯定不會產生死鎖。
5.1.5、如何避免死鎖
(1)開放呼叫
不要在持有鎖的情況下呼叫其他方法,所以要盡量縮小鎖的範圍,只對共享可變變數的操作上鎖即可。
這種方法是避免了迴圈等待條件的形成。
(2)固定獲取資源的順序
對於執行緒獲取資源的順序進行限制,可以對資源進行大小排序,獲取資源時要從最大的資源開始獲取。
這種方法也是避免了迴圈等待條件的形成。
(3)使用超時鎖
超時鎖可以在鎖使用一段時間後,自動釋放鎖,詳見?顯示鎖
這種方法是打破了不剝奪條件。
5.2、飢餓
由於程序的優先順序過低而一直獲取不到cpu的執行權。這種問題稱為飢餓。
所以我們盡量不要設定程序的優先順序,都是用預設優先順序即可。
5.3、活鎖
當多個相互協作的執行緒都對彼此進行響應從而修改各自的狀態,並使得任何乙個執行緒都無法繼續執行,就發生了活鎖。
避免活鎖的方法是在重試機制中加入隨機性。
處理併發性問題
多使用者客戶端 伺服器應用程式中的併發性 資料處理的策略 處理併發性問題的若干種方法 1 保守方式 這種併發性模型在資料上加了鎖。如果乙個使用者已經開啟了一條記錄,那麼在允許編輯的環境中,系統就會拒絕來自其他使用者的讀取資料的請求。2 開放方式 在開放的併發模型中,總是允許使用者讀取資料,甚至還可能...
併發程式設計中的原子性問題,可見性問題,有序性問題。
原子性問題 在乙個執行緒中,對乙個32的二進位制數進行賦值操作,當低16位的資料寫入後,發生了中斷,而此時又有乙個執行緒去讀取這個寫入的資料,必定得到的是乙個錯誤的資料。在j a中這種情況是不存在的,因為對基本資料型別的寫入和賦值保證了原子性 i 10 但僅限制於對基本資料型別,而變數的賦值就不能保...
併發中的原子性問題
高階語言的程式中,一條程式 可能對應多個cpu指令,而原子性,即指乙個或多個操作在cpu中執行的過程中不被中斷,稱為 原子性 而因為原子性出現的bug的原因是因為執行緒切換,即指乙個變數的讀取操作在cpu中可能存在多個執行緒同一時間執行不同的順序,導致值的不對。怎麼解決這個問題呢?原子性問題的根源,...