碼農翻身之我是一個線程
文章目錄
1. "我"的宿命 ----> 處理包裹
1.1 計算機世界規則
- 不知何時被選中執行任務
- 執行過程中隨時可能被打斷
- 有硬盤、數據庫等耗時操作需要讓出CPU等待
- 數據來了也得等CPU挑選
1.2 "我"的處理流程圖
2. "我"的小夥伴們
- Memcached 線程: 分佈式緩存用戶數據
- 數據庫連接線程: 他們也有一個線程池
3. "鎖"出的問題
3.1 存取款操作需加鎖後執行,例如:
1 沒加鎖時操作情況
線程1:存入300元 | 線程2:取出200元 |
---|---|
獲取當前餘額:1000 | —— |
計算最新餘額:1000 + 300 = 1300 | —— |
線程中斷,等待下次系統挑中執行 | —— |
—— | 獲取當前餘額:1000 |
—— | 計算最新餘額:1000 - 200 = 800 |
—— | 線程中斷,等待下次被系統挑中執行 |
再次執行,更新餘額:1300 | —— |
—— | 再次執行,更新餘額:800 (存的錢丟了) |
2 加鎖時操作情況
線程1:存入300元 | 線程2:取出200元 |
---|---|
獲取賬戶A的鎖:成功 | —— |
獲取當前餘額:1000 | —— |
計算最新餘額:1000 + 300 = 1300 | —— |
線程中斷,等待下次系統挑中執行 | —— |
—— | 獲取賬戶A的鎖:失敗,進入阻塞狀態 |
被系統選中,更新餘額:1300 | —— |
釋放賬戶A的鎖 | —— |
—— | 獲取賬戶A的鎖:成功 |
—— | 獲取當前餘額:1300 |
—— | 計算最新餘額:1300 - 200 = 1100 |
—— | 更新餘額:1100 |
—— | 釋放賬戶A的鎖 |
3.2 死鎖的發生
見下圖:
線程1:演員 -> 導演 | 線程2:導演 -> 演員 |
---|---|
獲取演員的鎖:成功 | —— |
線程中斷,等待下次系統挑中執行 | —— |
—— | 獲取導演的鎖:成功 |
—— | 線程中斷,等待下次系統挑中執行 |
獲取導演的鎖:失敗,繼續等待 | —— |
—— | 獲取演員的鎖:失敗,繼續等待 |
最終只好幹掉一個線程,來保證正常執行
3.3 死鎖的解決:新規則
至此,新建立一個規則:獲取資源的鎖之前,必須先讓所有資源統一進入一個算法,計算資源的優先級;並且永遠按照從小到大的方式獲取鎖。如下表所示:
PS: 這裏假設導演的優先級大於演員的優先級
線程1:演員 -> 導演 | 線程2:導演 -> 演員 |
---|---|
獲取導演的鎖:成功 | —— |
線程中斷,等待下次系統挑中執行 | —— |
—— | 獲取導演的鎖:失敗,繼續等待 |
獲取演員的鎖:成功 | —— |
執行轉賬 | —— |
釋放演員的鎖 | —— |
釋放導演的鎖 | —— |
—— | 獲取導演的鎖:成功 |
—— | 獲取演員的鎖:成功 |
—— | 執行轉賬 |
—— | 釋放演員的鎖 |
—— | 釋放導演的鎖 |
注意:1. 釋放鎖的時候最好是從優先級小的資源開始釋放
2. 所謂優先級的大小,實際就是將該資源變成一個數來比較,例如,用字符串的hashcode來比較。
後續內容更加精彩,江湖再見~