springboot整合redis分布式锁(普通锁+秒杀锁) demo代码

配置redis可参考: springboot整合redis+连接池+配置redis key过期事件监听 demo代码
对redis要求严格的推荐使用redission分布式锁

1.redis 分布式锁 工具类demo

/**
 * 描述:
 * redis 分布式锁 工具类demo
 * @author 闲走天涯
 * @create 2021/8/7 15:00
 */
public class RedisLockUtil {
    private String key;
    private Object value;
    private RedisTemplate<String,Object> redisTemplate;
    private Integer time;
    private TimeUnit timeUnit;

    public RedisLockUtil(){}

    public RedisLockUtil(RedisTemplate<String, Object> redisTemplate,String key) {
        this.redisTemplate = redisTemplate;
        this.key = key;
        this.value="1";
    }

    public RedisLockUtil(RedisTemplate<String, Object> redisTemplate,String key, Integer time,TimeUnit timeUnit) {
        //默认 为 1秒
        if(timeUnit==null){timeUnit=TimeUnit.SECONDS;}
        if(time==null || time<=0){time=1;}
        this.time = time;
        this.timeUnit=timeUnit;
        this.redisTemplate = redisTemplate;
        this.key = key;
        this.value = getTimeByPattern(time,timeUnit);
    }

    /**
     * 这种锁存在一定问题,官方推荐使用Redisson实现分布式锁
     * redis 分布式锁机制-加锁
     * value 是 时间数字来进行判断,例如时间戳是以毫秒为单位,表示每一毫秒为一次锁,超过则锁过期
     * 此处 value 为时间戳,用来进行判断是否同一段代码
     * 此处代码是 (秒杀系统)的方式,同一时间戳不能同时进行
     * @return
     */
    public boolean seckill_lock(){
        try {
            // 可以设置返回true
            Boolean isLock = redisTemplate.opsForValue().setIfAbsent(key, value);
            if (isLock) {
                return true;
            }
            Object obj = redisTemplate.opsForValue().get(key);
            String currentValue = obj==null?null:String.valueOf(obj);
            // 如果锁已经过期
            if (currentValue!=null && currentValue.length()>0
                    && Long.valueOf(currentValue) < getTimeByPattern(time,timeUnit)) {
                //获取上一个锁的时间 如果高并发的情况可能会出现已经被修改的问题  所以多一次判断保证线程的安全
                // 获取上一个锁的时间,并设置新锁的时间
                //getAndSet 获取原来key键对应的值并重新赋新值。
                String oldValue = String.valueOf(redisTemplate.opsForValue().getAndSet(key, value));
                if (oldValue!=null && oldValue.length()>0
                        && oldValue.equals(currentValue)) {
                    System.out.println("锁过期并返回true");
                    return true;
                }
            }
        }catch (Exception e){
            e.printStackTrace();
            System.out.println("redis分布式锁,加锁异常");
        }
        return false;
    }

    /**
     * 这种锁存在一定问题,官方推荐使用Redisson实现分布式锁
     * redis 锁机制-解锁
     * value 为时间戳,用来进行判断是否同一段代码
     * 此处代码是 (秒杀系统)的方式,同一时间戳不能同时进行
     * @return
     */
    public void seckill_unlock(){
        try {
            Object obj = redisTemplate.opsForValue().get(key);
            String currentValue = obj==null?null:String.valueOf(obj);
            if (currentValue!=null && currentValue.length()>0
                    && currentValue.equals(value)) {
                redisTemplate.opsForValue().getOperations().delete(key);
            }
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("redis分布式锁,解锁异常");
        }
    }

    /**
     * 获取当前时间-格式
     * @param time 时间数值
     * @param timeUnit 时间单位
     * @return
     */
    public long getTimeByPattern(Integer time,TimeUnit timeUnit){
        long millis = System.currentTimeMillis();
        return millis/timeUnit.toMillis(time);
    }

    /**
     * redis 锁机制-加锁
     * 普通锁
     * @return
     */
    public boolean lock(){
        try {
            //判断是否设置过期时间,设置过期时间可以让锁更有效运行
            //不设置时间可能导致锁长期存在导致异常
            if(time!=null && time>0){
                // 可以设置返回true/false
                return redisTemplate.opsForValue().setIfAbsent(key, value,time,timeUnit);
            }else{
                return redisTemplate.opsForValue().setIfAbsent(key, value);
            }
        }catch (Exception e){
            e.printStackTrace();
            System.out.println("redis 锁,加锁异常");
        }
        return false;
    }

    /**
     * redis 锁机制-解锁
     * 普通锁
     * @return
     */
    public void unlock(){
        try {
            redisTemplate.opsForValue().getOperations().delete(key);
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("redis 锁,解锁异常");
        }
    }
}

2.redis 多线程测试接口-分布式锁

/**
 * 描述:
 * redis demo接口
 * @author 闲走天涯
 * @create 2021/8/6 14:31
 */
@Slf4j
@RestController
@RequestMapping("/redis")
public class RedisController {
    @Autowired
    private RedisTemplate redisTemplate;

    //stringRedisTemplate 和 redisTemplate的区别:
    // stringRedisTemplate是redisTemplate的之类,格式为<String,String>
    //@Autowired
    //private StringRedisTemplate stringRedisTemplate;
	// 线程共享变量 初始化
    private volatile int num=100;

	/**
     * 多线程方式测试redis分布式锁
     * @param num2 自定义num次数
     * @return
     */
    @RequestMapping("/thread")
    public String redisThread(@RequestParam(required = false) Integer num2){
        if(num2!=null && num2>0) {
            this.num = num2;
        }
        for(int i=0;i<10;i++) {
            new Thread(() -> {
                while(num>0){
                    //new RedisLockUtil 工具类对象
                    //RedisLockUtil lockUtil = new RedisLockUtil(redisTemplate,"lock_redis");
                    RedisLockUtil lockUtil = new RedisLockUtil(redisTemplate,"lock_redis",1,TimeUnit.SECONDS);
                    boolean lock = lockUtil.lock();
                    //秒杀锁 适用于快速操作执行 例如秒杀系统
//                    boolean lock = lockUtil.seckill_lock();
					//普通锁
                    //boolean lock = lockUtil.lock();
                    if(lock) {
                        if(num<=0){
                            break;
                        }
                        System.out.println("print out num=" + num);
                        try {
                            Thread.sleep(200);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        num--;
                        //普通锁-解锁
                        lockUtil.unlock();
                        //秒杀锁-解锁
//                        lockUtil.seckill_unlock();
                    }else{
                        //System.out.println("锁定中");
                    }
                }
            }).start();
        }
        return "print success";
    }
}

3.测试例子

http://127.0.0.1:1234/redis/thread?num2=100
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值