有时候需要避免代码并发执行.
缓存击穿问题.
比如一件商品编号1001
.在缓存中它的key为goods:1001
,请求时,如果缓存中不存在,就读数据库,并设置缓存
if (读缓存 == null){
//读数据库
//设置缓存
}
此时一万个用户并发访问,读缓存为空,那么一万个请求会同时到达数据库.
期望的是:缓存为空时,只有一个线程进入if
判断,进行读库操作
java中有同步锁synchronized
很容易就能实现.
php中可以用
文件锁
来达到同样的效果.
- 以缓存中的key作为文件名,生成一个文件.
- 给这个文件上锁.
- 判断上锁是否成功,成功则进行读库操作.
代码如下
# FileLock.php
<?php
namespace lock;
class FileLock
{
private $fp;//文件描述符
/**
* FileLock constructor.
* @param string $key 缓存中的key,用来作为文件名
*/
public function __construct ($key) {
$this->makeFile($key);
}
/**
* 生成一个文件
* @param string $key 文件名
*/
private function makeFile($key){
$fp = fopen($key,'a');//生成文件,不存在就创建
$this->fp = $fp;//记录描述符
}
/**
* 获取锁
* @ LOCK_EX 独占锁
* @ LOCK_NB 获取锁失败时,不阻塞线程,直接返回
* @return bool
*/
public function getLock(){
return flock($this->fp,LOCK_EX|LOCK_NB);
}
/**
* 释放锁
* @return bool
*/
public function clearLock(){
return flock($this->fp,LOCK_UN);
}
}
测试效果
<?php
use lock\FileLock;
require_once 'FileLock.php';
if (!isset($argv[1])){
echo '输入cacheKey';
return;
}
//获取输入的cacheKey
$cacheKey = $argv[1];
$fileLock = new FileLock($cacheKey);
if ($fileLock->getLock())
{
echo "读库-$cacheKey".PHP_EOL;
sleep(60);
//TODO 设置缓存
$fileLock->clearLock();
}else{
echo "获取锁失败$cacheKey";
}
第一个终端 image.png 第二个 image.png 第三个 image.png执行结果
网友评论