php學習之併發控制中的獨佔鎖

2021-07-23 21:03:06 字數 2560 閱讀 2536

在php開發

1.併發問題

併發大家都知道是什麼情況,這裡說的是併發多個請求搶占同乙個資源,直接上例項吧

請求:index.php?mod=a&action=b&taskid=6

處理:$key = "a_b::".$uid.'_'.$taskid;

$v = $redis->get($key);

if($v == 1){

$redis->setex($key,10,1);

//處理邏輯省略

2.分析

邏輯看來還可以,結果發現資料庫中寫入了兩個同樣的請求結果,我看了記錄的時間戳,天

!居然是同一秒.

我用microtime(true) log一下兩個請求的時間差居然相差了

0.0001s

,就是說

$redis->setex($key,10,1);

還沒執行成功 第二個請求已經

get到跟第乙個請求一樣的結果。這不就是傳說中的併發搶占資源。這中情況 聽過很多,在開發過程中也沒刻意去模擬實驗過。

3.解決

方案1:第一反應就是要給處理過程加事務

(資料庫是

mysql innodb)

,加事務的結果就是 第乙個請求成功了 第二個請求會執行到後面撿查發現重了會回滾。其實

mysql

事務在保證資料一致性上是很

ok的,但是通過回滾來保證唯一資源獨佔代價太大,做過

mysql

事務測試測同學都知道,事務中的

insert

是已經插進去了,回滾之後才刪掉的。

方案2:還有乙個選擇就是

php中的檔案獨佔鎖,那就是說這情況下我要新建 使用者數

* 任務數的檔案來實現每個請求資源的獨佔,如果獨佔資源較少的話可選的解決辦法:

* 加鎖

public function file_lock($filename){

$fp_key = sha1($filename);

$this->fps[$fp_key] = fopen($filename, 'w+');

if($this->fps[$fp_key]){

return flock($this->fps[$fp_key], lock_ex|lock_nb);

return false;

* 解鎖

public function file_unlock($filename){

$fp_key = sha1($filename);

if($this->fps[$fp_key] ){

flock($this->fps[$fp_key] , lock_un);

fclose($this->fps[$fp_key] );

方案3:發現

$redis->setnx()

可以提供原子操作的狀態:相同的

key執行

setnx

之後沒過期或者沒

del,再執行會返回

false

。這就讓兩個以上的併發請求得到控制必須成功獲取鎖才能繼續。

*  加鎖

public function task_lock($taskid){

$expire = 2;

$lock_key ='task_get_reward_'.$this->uid.'_'.$taskid;

$lock = $this->redis->setnx($lock_key , time());//設當前時間

if($lock){

$this->redis->expire($lock_key,  $expire); //如果沒執行完

2s鎖失效

if(!$lock){//如果獲取鎖失敗 檢查時間

$time = $this->redis->get($lock_key);

if(time() - $time  >=  $expire){//新增時間戳判斷為了避免

expire

執行失敗導致死鎖 當然可以用

redis

自帶的事務來保證

$this->redis->rm($lock_key);

$lock =  $this->redis->setnx($lock_key , time());

if($lock){

$this->redis->expire($lock_key,  $expire); //如果沒執行完

2s鎖失效

return $lock;

*  解鎖

public function task_unlock($taskid){

$this->set_redis();

$lock_key = 'task_get_reward_'.$this->uid.'_'.$taskid;

$this->redis->rm($lock_key);

說明下setnx 和

expire

這兩個操作其實可以用

redis

事務來保證一致性

php 併發控制中的獨佔鎖

併發大家都知道是什麼情況,這裡說的是併發多個請求搶占同乙個資源,直接上例項吧 請求 index.php?mod a action b taskid 6 處理 key a b uid.taskid v redis get key if v 1 邏輯看來還可以,結果發現資料庫中寫入了兩個同樣的請求結果,...

JUC併發基石之AQS原始碼解析 獨佔鎖的釋放

juc併發基石之aqs原始碼解析 獨佔鎖的獲取public final boolean release int arg return false 獨佔鎖的涉及到兩個函式的呼叫 1.tryrelease arg 該方法由aqs的子類來實現釋放鎖的具體邏輯 2.unparksuccessor h 喚醒後...

併發程式設計核心框架AQS之獨佔鎖原理詳解

如何設計符合冪等性的高質量restful api 理解restful的冪等性,並且設計符合冪等規範的高質量restful api。http冪等方法,是指無論呼叫多少次都不會有不同結果的 http 方法。不管你呼叫一次,還是呼叫一百次,一千次,結果都是相同的。還是以之前的博文的例子為例。get tic...