乐观锁悲观锁使用场景请看这篇
乐观锁悲观锁使用场景
一: 悲观锁
特性:
1:互斥性,一个线程获取后其他不能获取,等待或者返回false
2:不能死锁,超时应该自动释放
3:锁应该只能由加锁人解锁
下面是redis 实现的伪代码
/**
* Class RedisLock
* @package app\common\model
*/
class RedisLock {
private $redis;
private $lock;
public function __construct($redis)
{
$this->redis=$redis;
}
/**
* @param $key 锁名
* @param int $overtime 锁超时时间单位秒
* @param int $waittime 等待超时时间,可能会阻塞线程,单位秒
*/
public function lock($key,$overtime=5,$waittime=0){
$time=microtime(true);
//用随机字符串防止被别的线程删除
$this->lock=rand_string(16);
//参数 nx 代表key不存在才操作, ex 缓存有效时间
$ok = $this->redis->set($key, $this->lock, array('nx', 'ex' => $overtime));
if ($ok) {
return $this->lock;
}
//循环获取,默认不等待
while (microtime(true)-$time>$waittime){
//睡眠1ms
usleep(1000);
//参数 nx 代表key不存在才操作, ex 缓存有效时间
$ok = $this->redis->set($key, $this->lock, array('nx', 'ex' => $overtime));
if ($ok) {
return $this->lock;
}
}
return false;
}
/**
* @param $key 加锁的key
* @return bool
*/
public function unlock($key){
if (!empty($this->lock)){
$lock=$this->redis->get($key);
if (!empty($lock)&&$lock==$this->lock){
return $this->redis->del($key);
}
}
return false;
}
}
PS:Redis 可以使用lua 脚本实现多个命令的原子性,详情自行搜索
二:乐观锁
特性:
1:不锁定资源
2:在提交时才检验数据是否被修改
乐观锁实现伪代码
public function lgLock($key){
//获取原始数据
$data=$redis->get($key);
//添加观测
$redis->watch($key);
//事务
$redis->multi();
//do something
//简单粗暴,原始数据没有被修改直接更新,修改了直接失败
return $redis->exec();
}
redis乐观锁使用注意看这里
Redis 乐观锁watch,multi 顺序