能,但仅限同一文件、同一进程组且正确调用时有效;它是建议性锁,依赖所有进程主动配合,不跨文件、不跨语言、在NFS等网络文件系统中可能失效。

PHP 用 flock() 锁文件真的能防并发写入吗
能,但只在「同一文件、同一进程组、正确调用」的前提下有效。它不是全局锁,不跨文件生效,也不阻塞其他语言或未调用 flock() 的 PHP 进程。常见误用是以为加了 flock() 就万事大吉,结果多个请求仍写乱数据。
关键点:
-
flock()是 advisory lock(建议性锁),依赖所有参与者主动配合 —— 没调用它,就完全无视这个锁 - 必须在
fopen()后、任何读写前加锁;锁在fclose()或脚本结束时自动释放 - 不能对已关闭的文件句柄调用
flock(),否则返回false且无警告 - 网络文件系统(如 NFS)下
flock()可能失效,不推荐用于 NAS 或容器共享卷
创建文件前先锁定目标路径的正确姿势
很多人想“锁住一个路径”,但 flock() 只作用于打开的文件句柄,无法锁定路径本身。所以标准做法是:先打开一个**固定存在的锁文件**(如 app.lock),再对其加锁,之后才操作目标文件(如生成 data_20241105.json)。
示例流程:
立即学习“PHP免费学习笔记(深入)”;
$fp = fopen('/var/lock/app.lock', 'c+');
if ($fp && flock($fp, LOCK_EX)) {
// 此处安全:可放心创建/写入其他文件
file_put_contents('/tmp/data.json', json_encode($data));
flock($fp, LOCK_UN); // 主动解锁更稳妥
}
fclose($fp);
注意:'c+' 模式确保文件存在且可读写,避免因文件不存在导致 fopen() 失败。
云模块_YunMOK网站管理系统采用PHP+MYSQL为编程语言,搭载自主研发的模块化引擎驱动技术,实现可视化拖拽无技术创建并管理网站!如你所想,无限可能,支持创建任何网站:企业、商城、O2O、门户、论坛、人才等一块儿搞定!永久免费授权,包括商业用途; 默认内置三套免费模板。PC网站+手机网站+适配微信+文章管理+产品管理+SEO优化+组件扩展+NEW Login界面.....目测已经遥遥领先..
flock() 阻塞 vs 非阻塞:选错会卡死整个请求
默认 flock($fp, LOCK_EX) 是阻塞的 —— 如果锁被占,当前 PHP 进程会一直等,直到超时或锁释放。在 Web 场景下这极易引发请求堆积、Apache/PHP-FPM 进程耗尽。
更安全的做法是用非阻塞模式 + 重试逻辑:
- 用
flock($fp, LOCK_EX | LOCK_NB),失败立即返回false - 手动 sleep + retry(最多 3–5 次,每次 50–100ms)
- 超过重试次数直接报错或降级(如写入临时文件,异步合并)
- 不要用
LOCK_SH替代LOCK_EX来“提速”——共享锁无法防止并发写
比文件锁更稳的替代方案有哪些
当业务要求强一致性(比如订单号生成、库存扣减),纯 flock() 不够可靠。可考虑:
- 数据库行锁:
SELECT ... FOR UPDATE在事务中锁定记录,由 DB 保证原子性 - Redis 原子命令:
SET key value NX EX 30实现带过期时间的分布式锁(注意要处理锁续期和崩溃释放) - 专用锁服务:如 etcd 的 lease + compare-and-swap,适合多语言混合架构
文件锁只适合单机、低频、非核心场景(如缓存刷新、日志轮转)。一旦涉及金额、状态变更、高并发,别硬扛。










