掃二維碼與項目經(jīng)理溝通
我們在微信上24小時期待你的聲音
解答本文疑問/技術(shù)咨詢/運(yùn)營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流
死鎖是指兩個或兩個以上的線程在執(zhí)行過程中,因爭奪資源而造成的一種互相等待的現(xiàn)象。若無外力作用,它們都將無法推進(jìn)下去。

目前創(chuàng)新互聯(lián)已為上1000家的企業(yè)提供了網(wǎng)站建設(shè)、域名、網(wǎng)頁空間、網(wǎng)站托管、服務(wù)器托管、企業(yè)網(wǎng)站設(shè)計、遂溪網(wǎng)站維護(hù)等服務(wù),公司將堅持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長,共同發(fā)展。
產(chǎn)生死鎖的四個必要條件得爛熟于心:
相應(yīng)的,如果想在程序運(yùn)行之前預(yù)防發(fā)生死鎖(也成為 “死鎖預(yù)防”),必須設(shè)法破壞產(chǎn)生死鎖的四個必要條件之一
光看羅列出來的幾點(diǎn)文字肯定還是不能完全理解,下面會結(jié)合實例來給大伙解釋。
用 Java 寫一個死鎖
這絕對是面試中 Java 手寫題的 TOP2!?。〕巳吮M皆知的手寫單例模式,手寫死鎖可能有些小伙伴會遺漏掉。
邏輯其實非常簡單,我們申請兩個資源,開兩個線程,每個線程持有其中的一個資源,并且互相請求對方的資源,就構(gòu)成了死鎖。
MySQL 經(jīng)典的死鎖案例
下面來看個 MySQL 經(jīng)典的死鎖案例:轉(zhuǎn)賬
A 賬戶給 B 賬戶轉(zhuǎn)賬 50 元的同時,B 賬戶也給 A 賬戶轉(zhuǎn)賬 30 元
正常情況下,如果只有一個操作,A 給 B 轉(zhuǎn)賬 50 元,可以在一個事務(wù)內(nèi)完成,先獲取 A 用戶的余額和 B 用戶的余額,因為之后需要修改這兩條數(shù)據(jù),所以需要通過寫鎖(for UPDATE)鎖住他們,防止其他事務(wù)更改導(dǎo)致我們的更改丟失而引起臟數(shù)據(jù)
但如果 A 給 B 轉(zhuǎn)賬和 B 給 A 轉(zhuǎn)賬同時發(fā)生,那就是兩個事務(wù),可能發(fā)生死鎖:
1)A 用戶給 B 用戶轉(zhuǎn)賬 50 元,需在程序中開啟事務(wù) 1 來執(zhí)行 SQL,獲取 A 的余額同時鎖住 A 這條數(shù)據(jù)。
2)B 用戶給 A 用戶轉(zhuǎn)賬 30 元,需在程序中開啟事務(wù) 2 來執(zhí)行 SQL,并獲取 B 的余額同時鎖住 B 這條數(shù)據(jù)。
3)在事務(wù) 1 中執(zhí)行剩下的 SQL,此時事務(wù) 1 是獲取不到 B 的鎖的,也即 select for update 就會被阻塞??;
4)同理,事務(wù) 2 繼續(xù)執(zhí)行剩下的 SQL,請求 A 的鎖,也是獲取不到的
事務(wù) 1 和事務(wù) 2 存在相互等待獲取鎖的過程,導(dǎo)致兩個事務(wù)都掛起阻塞,最終拋出獲取鎖超時的異常。
要想解決上述死鎖問題,我們可以從死鎖的四個必要條件入手。
指導(dǎo)思想其實很明確:就是保證 A 向 B 轉(zhuǎn)賬和 B 向 A 轉(zhuǎn)賬這兩個事務(wù)同一時刻只能有一個事務(wù)能成功獲取到鎖
由于互斥和不剝奪是鎖本質(zhì)的功能體現(xiàn),無法修改,所以咱們從另外兩個條件嘗試去解決。
1)破壞 “請求和保持” 條件:A 和 B 之間的操作用同一個鎖鎖?。ū热缬?Redis 分布式鎖做,A 和 B 之間的鎖的 key 表示為 A:B,可以讓 id 小的用戶排在前面,id 大的用戶排在后面,這樣來設(shè)計 key。如果存在分庫分表的情況,用 hashcode 來做比較也行),保證 A 向 B 轉(zhuǎn)賬和 B 向 A 轉(zhuǎn)賬這兩個事務(wù)同一時刻只能有一個事務(wù)能成功獲取鎖
2)破壞 “循環(huán)等待” 條件:先獲取更小的鎖,獲取到了小的鎖才能獲取大鎖(所謂小鎖還是大鎖,也可以簡單的根據(jù)用戶的 id 來進(jìn)行區(qū)分,先請求用戶 id 較小的,再請求用戶 id 較大的)。比如 A.id < B.id,那么 A 和 B 之間的操作,都是要先獲取 A 鎖,再獲取 B 鎖
具體代碼可參考如下:
? ?

我們在微信上24小時期待你的聲音
解答本文疑問/技術(shù)咨詢/運(yùn)營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流