分布式锁三种实现

一、基于Redis分布式锁(项目最常用,Redisson)

  1. 原生SET命令(原子加锁)
    // key:锁标识 value:唯一标识(UUID) NX不存在才设置 EX过期时间
    SET lock_key uuid NX EX 30
    • NX:互斥;EX:自动过期防死锁

• 解锁:必须校验value再DEL(避免删别人的锁),用Lua脚本原子解锁

if redis.call('get',KEYS1)==ARGV1 then return redis.call('del',KEYS1) else return 0 end

原生痛点:无锁续期、主从切换丢锁。

  1. Redisson(生产首选,封装好)

    RLock lock = redissonClient.getLock("stock_lock");

    // 尝试加锁,等待10s,持有30s自动过期

    boolean acquire = lock.tryLock(10,30,TimeUnit.SECONDS);

    if(acquire){

    try{

    //业务

    }finally {

    if(lock.isHeldByCurrentThread()) lock.unlock();

    }

    }

    核心特性

  2. 看门狗自动续期:业务没执行完,定时续过期时间,防止业务没做完锁过期

  3. 可重入锁:同一个线程多次加锁不会死锁

  4. 支持公平锁、读写锁

  5. RedLock解决Redis集群主从宕机丢锁问题(多节点加锁过半才算成功)

二、Zookeeper临时节点锁

  1. 抢锁:创建/lock临时有序节点

  2. 最小序号节点获得锁;其他节点监听前序节点

  3. 释放:断开连接临时节点自动删除,天然防死锁

• 优点:可靠性高、可重入、自动释放

• 缺点:性能差,zk频繁创建节点,高并发不用

三、数据库实现分布式锁

  1. 悲观锁:select ... for update

事务内锁定行,其他事务阻塞,依赖数据库行锁;长事务阻塞严重。

  1. 乐观锁:version版本号
    update stock set num=num-1,version=version+1 where id=1 and version=oldVersion;
    更新行数=0代表抢占锁失败,重试;适合高并发短事务。

四、选型对比

  1. 高并发、高性能 → Redisson(Redis)

  2. 可靠性优先、并发不高 → Zookeeper

  3. 无中间件,简单项目 → 数据库乐观锁

五、高频面试坑

  1. 死锁:加锁必须设置过期时间

  2. 锁失效误删:存唯一value,只有加锁线程能删锁

  3. 主从失效丢锁:Redis主没同步到从就宕机,RedLock或ZK规避

  4. 可重入:原生Redis不支持,Redisson内部计数实现可重入

相关推荐
天天被压力5 小时前
【A股分钟级高频数据完全手册 #07】北交所历史分钟K线接口:京市Pro版分时批量
java·人工智能·python
天天被压力5 小时前
【A股分钟级高频数据完全手册 #08】股票日、分时数据接口对比:普通分时与Pro版差异实测
java·人工智能·python
量化分析码农5 小时前
【Python量化波动率实战 01】波动率是怎么算的:年化、滚动与区间估计一次讲清
后端
特立独行的猫A5 小时前
AI 时代,我为什么推荐用 cj-tauri 开发桌面应用
java·后端·python
金銀銅鐵5 小时前
从一个类名到一张类图:用反射自动生成 PlantUML
java·后端·uml
疯华整猫5 小时前
被杀掉之后:我把 Android 的「唤起 + 常驻」重做了一遍
前端·面试·架构
追逐时光者6 小时前
一款基于 .NET 开源、免费的数据库自治诊断平台
后端·.net
nice_lcj5206 小时前
Java 并发容器入门:ConcurrentHashMap、CopyOnWriteArrayList、阻塞队列
java·面试·并发编程·阻塞队列·concurrenthashmap·copyonwritearraylist
微小的鱼6 小时前
Linux的渲染与显示系统链路
android·java·linux
追逐时光者6 小时前
让 GitHub Copilot 更懂你的 .NET 代码风格:一份精简实用的 Copilot Instructions
后端·.net