多執行緒讀寫優化(雙buff記憶體交換代替有鎖設計)

2021-08-21 15:51:12 字數 1231 閱讀 3524

目前有執行緒threada和threadb,乙個佇列queue。threada會對queue進行入隊操作,而threadb會對queue進行出隊操作。如下圖:

一般情況下,我們都會直接給queue上鎖,這樣就能保證多執行緒同時對queue進行操作時不會有問題。

直接加上鎖可以很容易就解決這個問題,但是也會帶來其他的問題:入隊操作一般幾乎不耗時,而出隊操作往往帶有其他一系列邏輯操作,所以會比較耗時。因此threada本來做完一系列入隊操作可能只要3ms,但是由於等待threadb的鎖的釋放,可能多等待了200ms。如下圖:

在這種情況下,如果threada在入隊操作還有其他邏輯,那麼後面的邏輯會被延後200ms執行,這是完全沒有必要的,因此便可以通過以下方式優化。

直接使用兩個queue物件,乙個只給threada用來入隊,乙個只給threadb用來出隊,這樣入隊和出隊操作就可以分離,不用去爭搶鎖。

達到一定觸發條件的時候兩個queue的記憶體就進行交換,原來入隊的queue變為出隊的queue,出隊的queue變成入隊的queue。這個觸發條件可以由threada來控制,在threada認為不需要繼續入隊並且threadb的隊列為空的時候,兩個queue可以進行交換。如下圖:

這樣之後,在時間上的表現就變為下圖。對於threada來講,一次將幾乎不耗時的入隊操作做完,後面如果有其他邏輯可以不會被耽誤。而對threadb來講,本來執行的操作可能就比較耗時,等待threada的入隊操作時間也非常短,所以影響不大。

可能讀者不太理解為什麼出隊操作會那麼耗時。因為上面是假設的出隊與後續邏輯操作連在一起的情況。

那麼是否意味著出隊之後直接釋放鎖,這種情況就不適用了呢?不是的。

入隊操作需要占用一次鎖和釋放一次鎖,出隊操作同樣是的。如果每出隊一次就需要占用和釋放一次鎖,那麼如果有100個就需要占用和釋放鎖一百次,這是在數量較多的情況下是非常消耗資源的了。

因此把鎖給去掉在這種情況下也是有相當的優化價值。

多執行緒讀寫mysql 多執行緒讀寫mysql資料庫

該樓層疑似違規已被系統摺疊 隱藏此樓檢視此樓 unsigned int stdcall scan pvoid pm char ip 20 strcpy ip,char pm mysql mysql mysql res result 初始化mysql控制代碼 mysql init mysql 連線my...

多執行緒優化

public void newexecute executorservice service executors.newfixedthreadpool threadnum 所有賬號總數 int accountcount accountdao.findallmerchantaccountcount i...

c mysql多執行緒 多執行緒讀寫mysql資料庫

該樓層疑似違規已被系統摺疊 隱藏此樓檢視此樓 unsigned int stdcall scan pvoid pm char ip 20 strcpy ip,char pm mysql mysql mysql res result 初始化mysql控制代碼 mysql init mysql 連線my...