redis實戰3 訊號槍的實現以及多版本訊號量

2021-10-04 19:28:40 字數 1711 閱讀 1349

訊號槍(semaphore),有時被稱為訊號燈,是在多執行緒環境下使用的一種設施,能保證乙個共同資源在某一段時間內只有有限數的執行緒能夠進行訪問的機制

基本思路:

1用zset有序集合來儲存資訊,鍵為隨機生成的id,值為當前的時間戳,

這樣zset會根據時間戳進行排序

2每次嘗試獲取訊號量之前,要先對集合進行過濾,刪除已經過期的訊號量

3插入訊號量到集合之後,要獲取當前的訊號量的排名在集合中的索引位置,只有足夠低的情況下(即要小於設定的臨界值,如小於5),才能表示獲取成功,否則就刪除集合中該訊號量元素

**:

public  string  acquire_semaphore

(int limit,

long time_out,string listname)

else

}

不足之處:

該程式執行雖然很快,但是無法保證併發情況下,如a,b兩個執行緒同時獲取了訊號量,則a,b在zset中的排名是相同的,這就造成了不公平情況的發生,這種情況也是併發環境下絕對會出現的情況,所以應該進行改進:

具體思路:

現在想要做的,是又想用時間戳來進行過期處理,又想要公平,所以就換個想法,用乙個計數器count來表示身份,每次嘗試獲取訊號量時,讓count自增獲取count的值,然後插入表中,但是在插入之前還要進行如下操作:

1用兩張表來儲存資料,一張是訊號量持有者表,另一張是超時有序集合

2每次儲存前,先對超時有序集合進行類似上述的過濾

3用zset的zinterstroe來獲取兩張表的交集

最後,執行插入,獲取排名,檢視是否排名是否夠低

**如下:

public

static string fair_semaphore

(string listname,

int limit,

long time_out)

else

}

有時候,我們不希望訊號量只能使用一定的時間,而是希望可以在使用的時候可以不斷的重新整理他的使用時間。這個時候我們可以這樣:

//訊號量重新整理:

public

boolean

fresh_semaphore

(string listname,string id)

return

true

;}

上述版本存在的問題:

如果a,b兩個執行緒爭奪訊號量,假設a先進行自增操作,但是b比a先插入有序集合,之後a再插入,排名比b低,又奪走了b的訊號量,而b只有再嘗試始放訊號或者重新整理訊號量時才會察覺這一點

解決辦法:加鎖處理

//帶有鎖的訊號量

public string semaphore_with_lock

(string listname,

int limit,

long time_out)

throws interruptedexception

finally

}return null;

}

這樣就能保證在同一時刻只有乙個能進行自增操作

讀書筆記 redis歷險和實戰3

redis持久化,一種是快照,一種是aof日誌,快照是全量備份,是記憶體資料的二進位制序列化,在儲存上緊湊,而日誌是連續的增量備份,是記憶體資料修改的指令記錄文字,時間越長,日誌變得越大,需要使用bgwriteaof對aof日誌重寫 原理是開闢子程序對記憶體遍歷,轉換一些列redis的操作指令,序列...

redis實戰 Redis命令之列表

列表的主要優點在於它可以包含多個字串值,使得使用者可以將資料集中在同乙個地方。redis允許使用者從序列的兩端推入或者彈出元素,獲取列表元素,以及執行各種常見的列表操作。命令用例 描述注意 rpush rpush key value value 從右端推入乙個或多個值 多個值用空格隔開 lpush ...

redis實戰 Redis命令之集合

redis的集合以無序的方式儲存多個各不相同的元素,使用者可以快速對集合執行新增元素 移除元素以及檢查元素是否存在於集合中的操作。命令用例 描述注意 sadd sadd key item item 將乙個或多個元素插入到集合中,並返回被新增元素當中原本不存在於集合中的數量 srem srem key...