springboot之redis的分布式锁

一、 测试

    @Autowired
    private RedisLockHelper redisLockHelper;

    private static final String LOCK ="lock:equipment";
   
    // 14: 48执行
    //@Scheduled(cron = "0 48 14 ? * *")
    public void orderSync()  {
        long time = System.currentTimeMillis() + (10*1000);
        //进行加锁操作
        if (redisLockHelper.lock(LOCK, time)) {
            System.out.println("加锁");
        }else {
            System.out.println("解锁");
            redisLockHelper.unlock(LOCK,time);
        }
    }

 

二、操作redis的工具类

package com.kmnfsw.util;


import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

/**
 *
 * @author wyg
 */
@Component
@Slf4j
public class RedisLockHelper {
    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 加锁
     * @param target   唯一标志
     * @param timeStamp  当前时间+超时时间 也就是时间戳
     * @return
     */
    public boolean lock(String target, long timeStamp){
        // 如果键不存在则新增,存在则不改变已经有的值。
        if(redisTemplate.opsForValue().setIfAbsent(target,timeStamp)){
            return true;
        }

        // 判断锁超时 - 防止原来的操作异常,没有运行解锁操作  防止死锁
        long currentLock = (long) redisTemplate.opsForValue().get(target);
        // 如果锁过期 currentLock不为空且小于当前时间
        if(currentLock < System.currentTimeMillis()){
            // 获取上一个锁的时间value 对应getset,如果lock存在 设置给过来的值,并返回旧的值
            long preLock = (long) redisTemplate.opsForValue().getAndSet(target,timeStamp);

            // 假设两个线程同时进来这里,因为key被占用了,而且锁过期了。获取的值currentLock=A(get取的旧的值肯定是一样的),两个线程的timeStamp都是B,key都是K.锁时间已经过期了。
            // 而这里面的getAndSet一次只会一个执行,也就是一个执行之后,上一个的timeStamp已经变成了B。只有一个线程获取的上一个值会是A,另一个线程拿到的值是B。
            if(preLock==currentLock){
                // preLock不为空且preLock等于currentLock,也就是校验是不是上个对应的商品时间戳,也是防止并发
                return true;

            }
        }
        return false;
    }


    /**
     * 解锁
     * @param target
     * @param timeStamp
     */
    public void unlock(String target,long timeStamp){
        try {
            long currentValue = (long) redisTemplate.opsForValue().get(target);
            if( currentValue<=timeStamp){
                // 删除锁状态
                redisTemplate.opsForValue().getOperations().delete(target);
            }
        } catch (Exception e) {
            log.error("警报!警报!警报!解锁异常{}",e);
        }
    }
}

 

你可能感兴趣的:(Spring,Boot)