All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.jiangkedev.lock.RedisDistributedLock Maven / Gradle / Ivy

The newest version!
package com.jiangkedev.lock;

import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.connection.RedisStringCommands;
import org.springframework.data.redis.connection.ReturnType;
import org.springframework.data.redis.connection.StringRedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.types.Expiration;
import org.springframework.stereotype.Component;

import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * @author jiangke
 * @date 16:51
 */
@Slf4j
@Component
public class RedisDistributedLock extends AbstractDistributedLock{
    private StringRedisTemplate redisTemplate;
    private ThreadLocal lockFlag = new ThreadLocal<>();
    private static final String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";

    public RedisDistributedLock(StringRedisTemplate redisTemplate){
        super();
        this.redisTemplate = redisTemplate;
    }
    @Override
    public boolean lock(String key,long expire,int retryTime,long sleepMills){
        boolean result = setRedis(key,expire);
        while((!result) && retryTime-- > 0){
            try{
                log.debug("lock faild, retrying..." +  retryTime);
                Thread.sleep(sleepMills);
            }catch (InterruptedException e){
                return false;
            }
            result = setRedis(key, expire);
        }
        return result;
    }
    private boolean setRedis(String key,long expire){
        try{
            boolean executeRes = redisTemplate.execute((RedisCallback) connection -> {
                StringRedisConnection  stringRedisConnection = (StringRedisConnection)connection;
                String uuid = UUID.randomUUID().toString();
                lockFlag.set(uuid);
                Boolean result = stringRedisConnection.set(key,uuid,Expiration.from(Duration.ofMillis(expire)),RedisStringCommands.SetOption.SET_IF_ABSENT);
                return result;
            });
            return executeRes;
        }catch (Exception e){
            log.error("set redis occured an exception:{}",e.getMessage());
        }
        return false;
    }
    @Override
    public boolean releaseLock(String key){
        // 释放锁的时候,有可能因为持锁之后方法执行时间大于锁的有效期,此时有可能已经被另外一个线程持有锁,所以不能直接删除
        try{
            List keys = new ArrayList<>();
            keys.add(key);
            List args = new ArrayList<>();
            args.add(lockFlag.get());
            List keysAndArgs = new ArrayList<>();
            keysAndArgs.addAll(keys);
            keysAndArgs.addAll(args);
            Long result = redisTemplate.execute((RedisCallback)connection->{
                StringRedisConnection  stringRedisConnection = (StringRedisConnection)connection;
                Long res = stringRedisConnection.eval(script,ReturnType.INTEGER,keys.size(), keysAndArgs.toArray(new String[keysAndArgs.size()]));
                return res;
            });
            return result > 0;
        }catch (Exception e){
            log.error("release lock occured an exception {}", e.getMessage());
        }
        return false;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy