1.Redis分布式锁实现思路
Redis实现分布式锁基于SetNx命令,因为在Redis中key是保证是唯一的。所以当多个线程同时的创建setNx时,只要谁能够创建成功谁就能够获取到锁。
Set 命令 每次set时,可以修改原来旧值;
SetNx命令 每次SetNx检查该key是否已经存在,如果已经存在的话不会执行任何操作。返回为0 如果已经不存在的话直接新增该key。
返回值: 1-新增key成功 0-失败
获取锁的时候:当多个线程同时创建SetNx k,只要谁能够创建成功谁就能够获取到锁。
释放锁:可以对该key设置一个有效期可以避免死锁的现象。
2.分布式锁的应用场景
- 分布式任务调度平台保证任务的幂等性。
- 分布式全局id的生成
- …
3.Redis分布式锁核心代码
封装的JedisUtil类可查看前面代码或者 完整的github项目 【springboot-redis(redis-lock)】
3.1 封装获取RedisLockUtil 工具类
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.UUID;
/**
* @author 若成风
* @description
* @date 2022/9/7 23:45
* @copyright (c) 2022, all rights reserved
**/
@Component
public class RedisLockUtil {
@Autowired
private JedisUtil jedisUtil;
private static final int setnxSuccss = 1;
/**
* 获取锁
* timeOut 时间为毫秒
* 示例: getLock("lockKey" , 3000, 5000)
* 申请尝试加锁,最大等待时间3秒,上锁5秒后自动解锁
* @param lockKey 定义锁的key
* @param lockWaitTimeOut 申请锁的最大等待时间,超过则申请锁失败
* @param lockTimeOut 锁的超时时间
* @return
*/
public String getLock(String lockKey, int lockWaitTimeOut, int lockTimeOut) {
// 获取Redis连接
// 定义没有获取锁的超时时间
Long endTimeOut = System.currentTimeMillis() + lockWaitTimeOut;
while (System.currentTimeMillis() < endTimeOut) {
String lockValue = UUID.randomUUID().toString();
// 如果在多线程情况下谁能够setnx 成功返回0 谁就获取到锁
Long nx = jedisUtil.setnx(lockKey, lockValue, lockTimeOut / 1000);
if (setnxSuccss == nx) {
return lockValue;
}
// 否则情况下 在超时时间内继续循环
}
return null;
}
/**
* 释放锁 其实就是将该key删除
* @return
*/
public Boolean unLock(String lockKey, String lockValue) {
// 确定是对应的锁 ,才删除
if (StringUtils.isNotBlank(lockValue) && lockValue.equals(jedisUtil.get(lockKey))) {
return jedisUtil.del(lockKey) > 0 ? true : false;
}
return false;
}
}
3.2测试使用分布式锁
import com.redmaple.common.util.RedisLockUtil;
import com.redmaple.service.OrderService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @author 若成风
* @description
* @date 2022/9/8 23:06
* @copyright (c) 2022, all rights reserved
**/
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
private RedisLockUtil redisLockUtil;
private String lockKey = "redmaple_lock";
@Async("myThreadPool")
@Override
public void testService() {
// 1.获取锁
String lockValue = redisLockUtil.getLock(lockKey, 500, 60000);
try {
if (StringUtils.isEmpty(lockValue)) {
System.out.println(Thread.currentThread().getName() + ",获取锁失败!");
return;
}
// 2.获取锁成功执行业务逻辑
System.out.println(Thread.currentThread().getName() + ",获取成功,lockValue:" + lockValue);
Thread.sleep(2000);
} catch (Exception e) {
log.error("分布式锁", e);
} finally {
// 防止代码执行完成后,或发生异常后,主动释放锁
// 3.释放lock锁
redisLockUtil.unLock(lockKey, lockValue);
}
}
}
@RestController
public class RedisLockController {
@Autowired
private OrderService orderService;
@GetMapping("/testRedisLock")
public String testRedisLock() {
System.out.println("===== start ======");
for (int i = 0; i < 10; i++) {
orderService.testService();
}
return "=== success ===";
}
}
如果该文章能够帮助到你,希望麻烦一键三连下,谢谢