1. 程式人生 > >(十五)java併發程式設計--執行緒的死鎖(deadlock)

(十五)java併發程式設計--執行緒的死鎖(deadlock)

執行緒在作業系統使用不同的資源,一般以以下方式使用這些資源。
1)請求一個資源。
2)使用這個資源。
3)釋放資源。

1、什麼是死鎖?

死鎖的情況是,一些執行緒被阻塞,每個執行緒都擁有一個資源,並且等待另外一個程序以獲取另外的一個資源。
想了想類似於生活中的哪些情形,我擁有有一本書(資源使用)叫做《java併發程式設計》 ,你擁有一本叫《java虛擬機器》,我需要你的才能把java理解的更好,你也需要我的書,我們都各自擁有一本,但都需要得到對方的書籍而完成某個“學習執行緒”,我等待著你使用完你的書籍,你也等待著我使用完我的本書,便互相等待, 形成了死鎖。(互相等待對方的資源,形成死迴圈,也許例子不太恰當)
相同的情形在作業系統中,當兩個或者多個執行緒擁有一些資源,並且等待其他下執行緒擁有的資源。
例如如下圖所示,執行緒1擁有資源1並且等待被執行緒2擁有的資源2, 而執行緒2擁有資源2但是,等待被執行緒1擁有的資源。
這裡寫圖片描述


出現死鎖的四個條件:
互斥:
執行緒的共享資源,為了執行緒安全可能需要同步(例如synchronized),也就是同一時刻只能有一個執行緒使用這個資源。
在某一個時刻這個資源只能被一個執行緒使用。
擁有鎖和等待:
一個執行緒至少擁有一個資源,並且等待其他資源。
不能強佔資源:一個執行緒不能獲取一個資源,除非另外一個執行緒釋放這個資源。
迴圈等待:
一些執行緒互相等待對方釋放資源,形成死迴圈。

2、解決死鎖的辦法?

1)避免死鎖和預防死鎖,不讓系統陷入死鎖狀態。
2)忽略死鎖問題,如果死鎖問題是非常罕見的,就讓他發生並重啟系統。這是windows和unix廣泛採取的方法。
3)

If you need to have multiple locks in your code, make sure everyone always acquire them in the same order.
如果在程式碼中需要多個鎖,確保程式碼每次請求他們的時候以相同的次序。

避免巢狀鎖。只需要所動需要鎖定的東西,而不是整個物件,如果符合我們的要求。
下面是典型的死鎖例子,如下程式碼。

package deadlock;

/**
 * `Created by fang on 2017/12/8.
 * 死鎖簡單示例.虛擬碼
 */
public class DeadLockDemo
{
public void methodA(){ synchronized (lockA){ //..... synchronized (lockB){ //... } } } public void methodB(){ synchronized (lockB){ //.... synchronized (lockA){ //...... } } } }

如上述虛擬碼,如果被多個執行緒呼叫可能會產生死鎖。這是因為物件 A B 以不同的次序鎖定。
這是絕大多數的死鎖的原因,所以想要避免他們,保證這些物件鎖是按順序進行的。

上述程式碼我們這麼解決死鎖呢?

上述根源是鎖的順序不對,對共享資源的鎖形成了迴圈等待,我們只需要按照同樣的次序鎖定就了。
解決方案虛擬碼如下。

//避免死鎖的虛擬碼.

    public void methodA(){
        synchronized (lockA){
            //.....




            synchronized (lockB){
                //...
            }
        }
    }

    public void methodB(){
        synchronized (lockA){
            //....


            synchronized (lockB){
                //......
            }
        }
    }

我們對物件A B加鎖兩個方法並一致的鎖的次序,解決了死鎖問題。

下篇再說一下,死鎖的解決方案,生產者和消費者模式。
小思:
自己不要死鎖自己,容易死迴圈,也要多執行緒,時間分片執行任務。
效率才是王道,如何提高自己的效率? 就是間作,”農作物間作套種方式”。