重入锁、死锁、活锁、公平非公平锁……一下子都给你屡清楚了
目錄
寫在前面
重入鎖
線程饑餓死鎖
死鎖
活鎖(Livelock)
公平鎖非公平鎖
互斥鎖
讀-寫鎖
寫在前面
? ? 每當聽公司大佬提起來,死鎖、活鎖、公平鎖、非公平鎖……自己也是知其然而不知其所以然。
? ? 自己特意去閱讀了《Java并發編程實戰》,終于將這些概念屢清楚了,在這里將自己的理解分享給大家。
重入鎖
? ? 所謂重入鎖,指的是以線程為單位,當一個線程獲取對象鎖之后,這個線程可以再次獲取本對象上的鎖,而其他的線程是不可以的。synchronized 和???ReentrantLock 都是可重入鎖。可重入鎖的意義在于防止死鎖。
線程饑餓死鎖
? ??在線程池中,如果任務依賴于其他任務,那么可能產生死鎖。在單線程的Executor中,如果一個任務將另一個任務提交到同一個Executor,并且等待這個被提交任務的結果,那么通常會引發死鎖。第二個任務停留在工作隊列中,并等待第一個任務完成,而第一個任務又無法完成,因為它在等待第二個任務的完成。在更大的線程池中,如果所有正在執行任務的線程都由于等待其他仍處于工作隊列中的任務而被阻塞,那么會發生同樣的問題。這種現象被稱為線程饑餓死鎖(Thread?Starvation Deadlock),只要線程池中的任務需要無限期地等待一些必須由池中其他任務才能提供的資源或條件,例如某個任務等待另一個任務的返回值或執行結果,那么除非線程池足夠大,否則將發生線程饑餓死鎖。
死鎖
? ? 每個人都擁有其他人需要的資源,同時又等待其他人已經擁有的資源,并且每個人在獲得所有需要的資源之前都不會放棄已經擁有的資源。線程A持有鎖L并想獲得鎖M的同時,線程B持有鎖M并嘗試獲得鎖L,那么這兩個線程將永遠等待下去。這種情況就是最簡單的死鎖形式。
活鎖(Livelock)
? ? 活鎖(Livelock)是另一種形式的活躍性問題,該問題盡管不會阻塞線程,但也不能繼續執行,因為線程將不斷重復執行相同的操作,而且總會失敗。
? ? 活鎖通常發生在處理事務消息的應用程序中:如果不能成功地處理某個消息,那么消息處理機制將回滾整個事務,并將它重新放到隊列的開頭,這樣一直處理這個消息,一直處理失敗,就會導致活鎖。
? ? 當多個相互協作的線程都對彼此進行響應從而修改各自的狀態,并使得任何一個線程都無法繼續執行,就發生了活鎖。
公平鎖非公平鎖
? ? 在公平的鎖上,線程將按照它們發出請求的順序來獲得鎖,但在非公平的鎖上,則允許“插隊”:當一個線程請求非公平的鎖時,如果在發出請求的同時該鎖的狀態變為可用,那么這個線程將跳過隊列中所有的等待線程并獲得這個鎖。
? ??在ReentrantLock的構造函數中提供了兩種公平性選擇:創建一個非公平的鎖(默認)或者一個公平的鎖。在公平的鎖上,線程將按照它們發出請求的順序來獲得鎖,但在非公平的鎖上,則允許“插隊”:當一個線程請求非公平的鎖時,如果在發出請求的同時該鎖的狀態變為可用,那么這個線程將跳過隊列中所有的等待線程并獲得這個鎖。(在Semaphore中同樣可以選擇采用公平的或非公平的獲取順序。)非公平的ReentrantLock并不提倡“插隊”行為,但無法按防止某個線程在合適的時候進行“插隊”。在公平的鎖中,如果有另一個線程持有這個鎖或者有其他線程在隊列中等待這個鎖,那么新發出請求的線程將被放入隊列中。在非公平的鎖中,只有當鎖被某個線程持有時,新發出的請求的線程才會被放入隊列中。
互斥鎖
? ? ReentrantLock實現了一種標準的互斥鎖:每次最多只有一個線程能持有ReentrantLock。但對于維護數據的完整性來說,互斥通常是一種過于強硬的加鎖規則,因此也就不必要地限制了并發性。互斥是一種保守的加鎖策略,雖然可以避免“寫/寫”沖突和“寫/讀”沖突,但同樣也避免了“讀/讀”沖突。
讀-寫鎖
? ? ReentrantReadWriteLock可以避免“讀/寫”沖突、“寫/寫”沖突,“讀/讀”是共享的。讀-寫鎖允許多個讀線程并發地訪問被保護的對象,當訪問以讀取操作為主的數據結構時,它能提高程序的可伸縮性。
總結
以上是生活随笔為你收集整理的重入锁、死锁、活锁、公平非公平锁……一下子都给你屡清楚了的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: jetty启停
- 下一篇: 什么是死锁?死锁如何解决