实例代码地址, 请前往: https://gitee.com/GuoqingLee/distributed-seckill
Redis 官方文档地址, 请前往: http://www.redis.cn/topics/distlock.html
前言
关于分布式锁的实现, 目前主流方案有以下三类:
1, 基于数据库的乐观锁;
2, 基于 Redis 实现的锁服务;
3, 基于 zookeeper 的实现;
网上关于怎么实现 Redis 的分布式锁, 一搜一大把的文章, 有写的比较好的, 也有明显存在缺陷的, 非常容易误导初入这一块的初学者;
而存在的问题, 无外乎是 setnx()-->expire(), 保证不了原子性, 容易出现死锁等情况, 这里就不在去做解释了;
本文的主旨是如何使用 Redis 官方推荐的 redisson 实现 Redis 的分布式锁;
一, 具体实现:
maven 引入需要的 jar
- <dependency>
- <groupId>org.redisson</groupId>
- <artifactId>redisson-spring-boot-starter</artifactId>
- <version>3.10.1</version>
- </dependency>
配置文件如下
- # common spring boot settings
- spring.Redis.database=
- spring.Redis.host=
- spring.Redis.port=
- spring.Redis.password=
- spring.Redis.ssl=
- spring.Redis.timeout=
- spring.Redis.cluster.nodes=
- spring.Redis.sentinel.master=
- spring.Redis.sentinel.nodes=
封装工具类:
- package cn.com.bluemoon.Redis.lock;
- import java.util.concurrent.TimeUnit;
- import org.redisson.API.RLock;
- import org.redisson.API.RedissonClient;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Component;
- /**
- * 基于 Redisson 的分布式锁实现
- * @author Guoqing.Lee
- * @date 2019 年 1 月 23 日 下午 4:04:57
- *
- */
- @Component
- public class RedissonDistributedLocker {
- @Autowired
- private RedissonClient redissonClient;
- /**
- * 加锁
- * @param lockKey
- * @return
- */
- public RLock lock(String lockKey) {
- RLock lock = redissonClient.getLock(lockKey);
- lock.lock();
- return lock;
- }
- /**
- * 加锁, 过期自动释放
- * @param lockKey
- * @param leaseTime 自动释放锁时间
- * @return
- */
- public RLock lock(String lockKey, long leaseTime) {
- RLock lock = redissonClient.getLock(lockKey);
- lock.lock(leaseTime, TimeUnit.SECONDS);
- return lock;
- }
- /**
- * 加锁, 过期自动释放, 时间单位传入
- * @param lockKey
- * @param unit 时间单位
- * @param leaseTime 上锁后自动释放时间
- * @return
- */
- public RLock lock(String lockKey, TimeUnit unit, long leaseTime) {
- RLock lock = redissonClient.getLock(lockKey);
- lock.lock(leaseTime, unit);
- return lock;
- }
- /**
- * 尝试获取所
- * @param lockKey
- * @param unit 时间单位
- * @param waitTime 最多等待时间
- * @param leaseTime 上锁后自动释放时间
- * @return
- */
- public boolean tryLock(String lockKey, TimeUnit unit, long waitTime, long leaseTime) {
- RLock lock = redissonClient.getLock(lockKey);
- try {
- return lock.tryLock(waitTime, leaseTime, unit);
- } catch (InterruptedException e) {
- return false;
- }
- }
- /**
- * 尝试获取所
- * @param lockKey
- * @param waitTime 最多等待时间
- * @param leaseTime 上锁后自动释放锁时间
- * @return
- */
- public boolean tryLock(String lockKey, long waitTime, long leaseTime) {
- RLock lock = redissonClient.getLock(lockKey);
- try {
- return lock.tryLock(waitTime, leaseTime, TimeUnit.SECONDS);
- } catch (InterruptedException e) {
- return false;
- }
- }
- /**
- * 释放锁
- * @param lockKey
- */
- public void unlock(String lockKey) {
- RLock lock = redissonClient.getLock(lockKey);
- lock.unlock();
- }
- /**
- * 释放锁
- * @param lock
- */
- public void unlock(RLock lock) {
- lock.unlock();
- }
- }
二, 使用方式
方式一:
- @Autowired
- private RedissonDistributedLocker redissonDistributedLocker;
- String lockKey = "BM_MARKET_SECKILL_" + stallActivityId;
- try {
- // 超过 2S 自动释放锁
- redissonDistributedLocker.lock(lockKey, 2L);
- // 业务处理
- } finally {
- redissonDistributedLocker.unlock(lockKey); // 释放锁
- }
方案二:
- @Autowired
- private RedissonDistributedLocker redissonDistributedLocker;
- public void test() throws InterruptedException {
- final int[] counter = {0};
- for (int i= 0; i < 100; i++){
- new Thread(new Runnable() {
- @Override
- public void run() {
- boolean isGetLock = redissonDistributedLocker.tryLock("test0001", 3L, 1L);
- if(isGetLock) {
- try {
- int a = counter[0];
- counter[0] = a + 1;
- logger.info(a + "");
- } finally {
- redissonDistributedLocker.unlock("test0001");
- }
- }
- }
- }).start();
- }
- // 主线程休眠, 等待结果
- Thread.sleep(5000);
- System.out.println(counter[0]);
- logger.info(counter[0] + "");
- }
闲话就不多说了, 希望能对你有所帮助.
来源: https://www.cnblogs.com/ocean-sky/p/10320627.html