当前位置:网站首页>如何用 Redis 实现一个分布式锁
如何用 Redis 实现一个分布式锁
2022-06-23 11:02:00 【InfoQ】
场景模拟

@RestController
public class SkillController {
@Autowired
private RedisTemplate redisTemplate;
// 秒杀接口
@RequestMapping("/deduct_stock")
public String deductStock() {
// 加锁
synchronized (this) {
int stock = Integer.parseInt(redisTemplate.opsForValue().get("stock").toString());
if (stock > 0) {
// 库存 -1
int realStock = stock - 1;
// 扣减库存
redisTemplate.opsForValue().set("stock", realStock + "");
System.out.println("扣减成功,剩余库存:" + realStock);
} else {
System.out.println("扣减失败,库存不足");
}
}
return "8080";
}
}
@RestController
public class SkillController {
@Autowired
private RedisTemplate redisTemplate;
// 秒杀接口
@RequestMapping("/deduct_stock")
public String deductStock() {
// 加锁
synchronized (this) {
int stock = Integer.parseInt(redisTemplate.opsForValue().get("stock").toString());
if (stock > 0) {
// 库存 -1
int realStock = stock - 1;
// 扣减库存
redisTemplate.opsForValue().set("stock", realStock + "");
System.out.println("扣减成功,剩余库存:" + realStock);
} else {
System.out.println("扣减失败,库存不足");
}
}
return "8090";
}
}


JVM 锁



Redis SETNX
@RestController
public class SkillController {
@Autowired
private RedisTemplate redisTemplate;
@RequestMapping("/deduct_stock")
public String deductStock() {
// 商品 ID,具体应用中应该是请求传入的
String lockKey = "lock:product_01";
// SETNX 加锁
Boolean result = redisTemplate.opsForValue().setIfAbsent(lockKey, "product");
// 如果为 false 说明这把锁存在,直接返回
if (!result) {
// 模拟返回业务
return "系统繁忙";
}
int stock = Integer.parseInt(redisTemplate.opsForValue().get("stock").toString());
if (stock > 0) {
// 库存 -1
int realStock = stock - 1;
// 扣减库存 模拟其他更多业务操作
redisTemplate.opsForValue().set("stock", realStock + "");
System.out.println("扣减成功,剩余库存:" + realStock);
} else {
System.out.println("扣减失败,库存不足");
}
// 加锁后需要释放锁
redisTemplate.delete(lockKey);
return "8080";
}
}try catchtry finally
Boolean result = redisTemplate.opsForValue().setIfAbsent(lockKey, "product");
redisTemplate.expire(lockKey, 10, TimeUnit.SECONDS);Boolean result = redisTemplate.opsForValue().setIfAbsent(lockKey, "product", 10, TimeUnit.SECONDS);
Redisson
@RestController
public class RedissonController {
@Autowired
private Redisson redisson;
@Autowired
private RedisTemplate redisTemplate;
@RequestMapping("/deduct_stock1")
public String deductStock() {
// 商品 ID,具体应用中应该是请求传入的
String lockKey = "lock:product_01";
// 获取锁
RLock lock = redisson.getLock(lockKey);
// 加锁
lock.lock();
try {
int stock = Integer.parseInt(redisTemplate.opsForValue().get("stock").toString());
if (stock > 0) {
// 库存 -1
int realStock = stock - 1;
// 扣减库存
redisTemplate.opsForValue().set("stock", realStock + "");
System.out.println("扣减成功,剩余库存:" + realStock);
} else {
System.out.println("扣减失败,库存不足");
}
} finally {
// 释放锁
lock.unlock();
}
return "8080";
}
}

lualuaRedissonLock.lock()--->lockInterruptibly()--->tryAcquire()--->tryLockInnerAsync()tryLockInnerAsync()<T> RFuture<T> tryLockInnerAsync(long leaseTime, TimeUnit unit, long threadId, RedisStrictCommand<T> command) {
internalLockLeaseTime = unit.toMillis(leaseTime);
return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, command,
// 如果锁不存在,则通过hset设置它的值,并设置过期时间
"if (redis.call('exists', KEYS[1]) == 0) then " +
"redis.call('hset', KEYS[1], ARGV[2], 1); " +
"redis.call('pexpire', KEYS[1], ARGV[1]); " +
"return nil; " +
"end; " +
// 如果锁已存在,其是当前线程,则通过hincrby给数值递增1,即锁的重入
"if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then " +
"redis.call('hincrby', KEYS[1], ARGV[2], 1); " +
"redis.call('pexpire', KEYS[1], ARGV[1]); " +
"return nil; " +
"end; " +
// 如果锁已存在,不是当前线程,则返回过期时间 ttl
"return redis.call('pttl', KEYS[1]);",
Collections.<Object>singletonList(getName()), internalLockLeaseTime, getLockName(threadId));
}RedissonLock.lock()--->lockInterruptibly()--->tryAcquire()--->scheduleExpirationRenewal()scheduleExpirationRenewal()lua// getName()就是当前锁的名字
RFuture<Boolean> future = commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
// 判断这个锁 getName() 是否在redis中存在,如果存在就进行 pexpire 延期 默认30s
"if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then " +
"redis.call('pexpire', KEYS[1], ARGV[1]); " +
"return 1; " +
"end; " +
"return 0;",
Collections.<Object>singletonList(getName()), internalLockLeaseTime, getLockName(threadId));
getName()pexpirelockWatchdogTimeout=30slockWatchdogTimeout/3=10s边栏推荐
- MySQL-02. Understanding of indexes at work
- Noi OJ 1.4 01: positive and negative C language
- 分享一个手游脚本源码
- php反射类使用
- 详解判断大小端的方法
- Over a year, time has changed. Chinese chips have made breakthroughs, but American chips are difficult to sell
- 最简单DIY基于蓝牙、51单片机和舵机的钢铁爱国者机关枪控制器
- list的介绍及使用
- Noi OJ 1.2 conversion between integer and Boolean C language
- 六张图详解LinkedList 源码解析
猜你喜欢

智慧园区效果不满意?请收下ThingJS这份秘籍

Pycharm installation tutorial, super detailed

Esp32-cam high cost performance temperature and humidity monitoring system

Simplest DIY remote control computer system based on STM32 ① (capacitive touch + key control)

Economic common sense

Solve the problem that Preview PDF cannot be downloaded

Installation and use of binabsinspector, an open source binary file static vulnerability analysis tool

ESP32-CAM高性价比温湿度监控系统

Install the typescript environment and enable vscode to automatically monitor the compiled TS file as a JS file

Step by step introduction to sqlsugar based development framework (9) -- Realizing field permission control with WinForm control
随机推荐
Parity of UART
Mysql-03. Experience of SQL optimization in work
JVM easy start-02
Go zero micro Service Practice Series (VI. cache consistency assurance)
flutter系列之:flutter中的Wrap
NOI OJ 1.3 05:计算分数的浮点数值 C语言
After repeated pressure, Apple may significantly increase the price of iphone14
程序中创建一个子进程,然后父子进程各自独自运行,父进程在标准输入设备上读入小写字母,写入管道。子进程从管道读取字符并转化为大写字母。读到x结束
Noi OJ 1.3 15: apple and bug C language
MySQL Basics - Notes
Unity technical manual - lifecycle lifetimebyemitterspeed - color in the cycle coloroverlifetime- speed color colorbyspeed
Simplest DIY remote control computer system based on STM32 ① (capacitive touch + key control)
圖片存儲--引用
Stockage d'images - référence
最简单DIY基于C#和51单片机上下位机一体化的PCA9685舵机控制程序
最简单DIY串口蓝牙硬件实现方案
ESP32-CAM高性价比温湿度监控系统
Noi OJ 1.3 05: floating point numeric C language for calculating fractions
Description of directory files of TLBB series of Tianlong Babu - netbill server [ultra detailed]
Not satisfied with the effect of the smart park? Please accept this secret script of thingjs