当前位置: 首页>后端>正文

Redisson分布式锁的使用(附源码)

问题背景

Redisson做分布式锁是目前比较流行的方式,但是在使用的过程中遇到一些坑:

  • Redisson的分布式锁只能通过创建锁的线程进行解锁,正所谓解铃还须系铃人,不是同一个线程解锁会报异常
  • 因为Redisson是为锁而生,所以一开始设计的时候,为了防止死锁,默认锁的过期时间为30S
  • 当时我居然傻到用单元测试来测试Redisson的分布式锁,我太傻了,单元测试之后马上就会结束项目运行,那么就没有线程持有锁了,更别说还需要同线程解锁了

注意事项:

  • 代码是从我的这篇文章进行添加修改的
  • 可以自己创建工程,也可以下载源码进行参考
  • 默认已安装redis,可以使用安装包安装看这篇文章,使用docker安装看这篇文章

项目搭建

1 redisson的默认锁时间为30s


Redisson分布式锁的使用(附源码),第1张

2 添加redisson工具类

package com.yg.redisson.utils;

import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;


@Slf4j
@Component
public class DistributedRedisLock {

    @Autowired
    private RedissonClient redissonClient;

    /**
     * 加锁
     *
     * @param lockName
     * @return
     */
    public Boolean lock(String lockName) {
        if (redissonClient == null) {
            log.info("DistributedRedisLock redissonClient is null");
            return false;
        }

        try {
            RLock lock = redissonClient.getLock(lockName);
            // 默认是30S释放锁, 这里设置12小时
            lock.lock(12 * 60 * 60L, TimeUnit.SECONDS);
            log.info(" lock [{}] success", lockName);

            return true;
        } catch (Exception e) {
            log.info("加锁失败", e);
            log.error("DistributedRedisLock lock [{}] Exception:", lockName, e);
            return false;
        }
    }


    /**
     * 加锁
     *
     * @param lockName
     * @return
     */
    public Boolean lockWithExpire(String lockName, long expire) {
        if (redissonClient == null) {
            log.info("DistributedRedisLock redissonClient is null");
            return false;
        }

        try {
            RLock lock = redissonClient.getLock(lockName);
            // 锁expire秒后自动释放,防止死锁
            lock.lock(expire, TimeUnit.SECONDS);
            // 加锁成功
            return true;
        } catch (Exception e) {
            log.info("加锁失败", e);
            log.error("DistributedRedisLock lock [{}] Exception:", lockName, e);
            return false;
        }
    }


    /**
     * 释放锁
     *
     * @param lockName
     * @return
     */
    public Boolean unlock(String lockName) {
        if (redissonClient == null) {
            log.info("DistributedRedisLock redissonClient is null");
            return false;
        }

        try {
            RLock lock = redissonClient.getLock(lockName);
            log.info("lock:{}", lock.isLocked());
            log.info("lock.isHeldByCurrentThread: {}", lock.isHeldByCurrentThread());
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
                log.info(" unlock [{}] success", lockName);
                return true;
            }
            return false;
        } catch (Exception e) {
            log.error("DistributedRedisLock unlock [{}] Exception:", lockName, e);
            return false;
        }
    }
}

3 添加使用分布式锁的服务

package com.yg.redisson.service;

import com.yg.redisson.utils.DistributedRedisLock;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;


/**
 * @Author suolong
 * @Date 2022/5/7 10:04
 * @Version 2.0
 */
@Slf4j
@Service
public class RedissonService {

    @Autowired
    DistributedRedisLock distributedRedisLock;

    @PostConstruct
    public void distributeLockTest(){
        String lockName = "yuange";
        //加锁
        if(distributedRedisLock.lock(lockName)){
            log.info("lock success");
            //do something  锁住你要执行的程序
            /*
    
             */
        }else{
            log.error("lock failed");
        }

        //解锁
        if(distributedRedisLock.unlock(lockName)){
            log.info("unlock success");
        }else{
            log.error("unlock failed");
        }
    }

}

4 项目目录


Redisson分布式锁的使用(附源码),第2张

总结

  • 如果被锁的逻辑会大于30s,需要自己设置过期时间
  • 需要同个线程进行解锁




作为程序员第 124 篇文章,每次写一句歌词记录一下,看看人生有几首歌的时间,wahahaha ...

Redisson分布式锁的使用(附源码),第3张

Lyric: 如果说分手是苦痛的起点


https://www.xamrdz.com/backend/3v81941231.html

相关文章: