怎么理解Redis中的分布式锁
发表于:2026-10-31 作者:千家信息网编辑
千家信息网最后更新 2026年10月31日,本篇内容介绍了"怎么理解Redis中的分布式锁"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Redi
千家信息网最后更新 2026年10月31日怎么理解Redis中的分布式锁
本篇内容介绍了"怎么理解Redis中的分布式锁"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
Redis 分布式锁
大家项目中都会使用到分布式锁把,通常用来做数据的有序操作场景,比如一笔订单退款(如果可以退多次的情况)。或者用户多端下单。【相关推荐:Redis视频教程】
Maven 依赖
我主要是基于 Spring-Boot 2.1.2 + Jedis 进行实现
4.0.0 org.springframework.boot spring-boot-starter-parent 2.1.2.RELEASE cn.edu.cqvie redis-lock 1.0-SNAPSHOT UTF-8 1.8 2.9.0 5.0.7 org.springframework.boot spring-boot-autoconfigure org.springframework.data spring-data-redis redis.clients jedis ${redis.version} org.springframework.boot spring-boot-starter-logging org.slf4j log4j-over-slf4j org.springframework.boot spring-boot-starter-test test org.springframework.boot spring-boot-maven-plugin
配置文件
application.properties 配置文件内容如下:
spring.redis.host=127.0.0.1spring.redis.port=6379spring.redis.password=spring.redis.timeout=30000spring.redis.jedis.pool.max-active=8spring.redis.jedis.pool.min-idle=2spring.redis.jedis.pool.max-idle=4logging.level.root=INFO
接口定义
接口定义,对于锁我们核心其实就连个方法 lock 和 unlock.
public interface RedisLock { long TIMEOUT_MILLIS = 30000; int RETRY_MILLIS = 30000; long SLEEP_MILLIS = 10; boolean tryLock(String key); boolean lock(String key); boolean lock(String key, long expire); boolean lock(String key, long expire, long retryTimes); boolean unlock(String key);}分布式锁实现
我的实现方式是通过 setnx 方式实现了,如果存在 tryLock 逻辑的话,会通过 自旋 的方式重试
// AbstractRedisLock.java 抽象类public abstract class AbstractRedisLock implements RedisLock { @Override public boolean lock(String key) { return lock(key, TIMEOUT_MILLIS); } @Override public boolean lock(String key, long expire) { return lock(key, TIMEOUT_MILLIS, RETRY_MILLIS); }}// 具体实现@Componentpublic class RedisLockImpl extends AbstractRedisLock { private Logger logger = LoggerFactory.getLogger(getClass()); @Autowired private RedisTemplate redisTemplate; private ThreadLocal threadLocal = new ThreadLocal(); private static final String UNLOCK_LUA; static { StringBuilder sb = new StringBuilder(); sb.append("if redis.call(\"get\",KEYS[1]) == ARGV[1] "); sb.append("then "); sb.append(" return redis.call(\"del\",KEYS[1]) "); sb.append("else "); sb.append(" return 0 "); sb.append("end "); UNLOCK_LUA = sb.toString(); } @Override public boolean tryLock(String key) { return tryLock(key, TIMEOUT_MILLIS); } public boolean tryLock(String key, long expire) { try { return !StringUtils.isEmpty(redisTemplate.execute((RedisCallback) connection -> { JedisCommands commands = (JedisCommands) connection.getNativeConnection(); String uuid = UUID.randomUUID().toString(); threadLocal.set(uuid); return commands.set(key, uuid, "NX", "PX", expire); })); } catch (Throwable e) { logger.error("set redis occurred an exception", e); } return false; } @Override public boolean lock(String key, long expire, long retryTimes) { boolean result = tryLock(key, expire); while (!result && retryTimes-- > 0) { try { logger.debug("lock failed, retrying...{}", retryTimes); Thread.sleep(SLEEP_MILLIS); } catch (InterruptedException e) { return false; } result = tryLock(key, expire); } return result; } @Override public boolean unlock(String key) { try { List keys = Collections.singletonList(key); List args = Collections.singletonList(threadLocal.get()); Long result = redisTemplate.execute((RedisCallback) connection -> { Object nativeConnection = connection.getNativeConnection(); if (nativeConnection instanceof JedisCluster) { return (Long) ((JedisCluster) nativeConnection).eval(UNLOCK_LUA, keys, args); } if (nativeConnection instanceof Jedis) { return (Long) ((Jedis) nativeConnection).eval(UNLOCK_LUA, keys, args); } return 0L; }); return result != null && result > 0; } catch (Throwable e) { logger.error("unlock occurred an exception", e); } return false; }} 测试代码
最后再来看看如何使用吧. (下面是一个模拟秒杀的场景)
@RunWith(SpringRunner.class)@SpringBootTestpublic class RedisLockImplTest { private Logger logger = LoggerFactory.getLogger(getClass()); @Autowired private RedisLock redisLock; @Autowired private StringRedisTemplate redisTemplate; private ExecutorService executors = Executors.newScheduledThreadPool(8); @Test public void lock() { // 初始化库存 redisTemplate.opsForValue().set("goods-seckill", "10"); List futureList = new ArrayList<>(); for (int i = 0; i < 100; i++) { futureList.add(executors.submit(this::seckill)); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } // 等待结果,防止主线程退出 futureList.forEach(action -> { try { action.get(); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } }); } public int seckill() { String key = "goods"; try { redisLock.lock(key); int num = Integer.valueOf(Objects.requireNonNull(redisTemplate.opsForValue().get("goods-seckill"))); if (num > 0) { redisTemplate.opsForValue().set("goods-seckill", String.valueOf(--num)); logger.info("秒杀成功,剩余库存:{}", num); } else { logger.error("秒杀失败,剩余库存:{}", num); } return num; } catch (Throwable e) { logger.error("seckill exception", e); } finally { redisLock.unlock(key); } return 0; }} 总结
本文是 Redis 锁的一种简单的实现方式,基于 jedis 实现了锁的重试操作。 但是缺点还是有的,不支持锁的自动续期,锁的重入,以及公平性(目前通过自旋的方式实现,相当于是非公平的方式)。
"怎么理解Redis中的分布式锁"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!
方式
分布式
内容
库存
场景
情况
接口
文件
更多
知识
剩余
配置
实用
有序
成功
学有所成
接下来
代码
公平性
困境
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
互联网科技公司经营范围
美国互联网科技
青岛互联网科技公司
奇酷互联网络科技公司
广西互联网科技公司
互联网金融监管科技
西藏七维空间互联网科技有限公司
科技互联网的估值
随着互联网科技发展
互联网企业和科技型企业
互联网时代科技改变生活
互联网对科技的发展
呼和浩特新华互联网科技学院
东莞新华互联网科技学校
工业互联网山东科技大学
电子商务与互联网科技的关系
中国互联网公司的科技投入
科技信息时代互联网发展
科技互联网专业工作会议发言稿
株洲百竞科技的互联网营销顾问
互联网佳科技有限公司
互联网金融 科技
科技服务与互联网
礼当家互联网科技
滨湖区互联网智能科技产品供应
昭通云南众福互联网科技有限公司
互联网金融科技展
上海京穆互联网科技有限公司
艺电能源互联网科技有限公司招聘
福仕德教育科技互联网