基于spring-boot-data-redis的分布式锁实现

基于spring-boot-data-redis的分布式锁实现

public class DistributedLock {

    private static final TimeUnit DEFAULT_UNIT = TimeUnit.SECONDS;
    private static final long DEFAULT_EXPIRE = 5L;
    private static final String DEFAULT_PREFIX = "CUSTOM:REDIS:LOCK:";
    private static final String REDIS_SUCCESS_STRING = "OK";

    private RedisTemplate redisTemplate;

    private String key;

    private long expire = DEFAULT_EXPIRE;

    private TimeUnit unit = DEFAULT_UNIT;

    private String value;

    public static DistributedLock newLock(String key) {
        return newLock(key, DEFAULT_EXPIRE, DEFAULT_UNIT);
    }

    public static DistributedLock newLock(String key, long expire, TimeUnit unit) {
        DistributedLock lock = new DistributedLock();
        lock.key = key;
        lock.expire = expire;
        lock.unit = unit;
        lock.value = UUID.randomUUID().toString();
        return lock;
    }

    public DistributedLock withValue(String value) {
        this.value = value;
        return this;
    }

    public DistributedLock ofRedisTemplate(RedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
        return this;
    }

    public boolean tryLock() {
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return 'OK' else return redis.call('set', KEYS[1], ARGV[1],'EX',ARGV[2],'NX') end";
        String result = (String) redisTemplate.execute(RedisScript.of(script, String.class), Collections.singletonList(getKey()), this.value, this.unit.toSeconds(this.expire) + "");
        return REDIS_SUCCESS_STRING.equals(result);
    }

    public boolean tryLock(long timeout, TimeUnit unit) {
        long during = unit.toMicros(timeout);
        long start = System.currentTimeMillis();
        while (true) {
            if (tryLock()) {
                return true;
            }
            long end = System.currentTimeMillis();
            if (end - start >= during) {
                break;
            }
        }
        return false;
    }

    public boolean release() {
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then redis.call('del', KEYS[1]) return 1 else return 0 end";
        Long result = (Long) redisTemplate.execute(RedisScript.of(script, Long.class), Collections.singletonList(getKey()), this.value);
        return result != null && result > 0;
    }

    private String getKey() {
        return DEFAULT_PREFIX + this.key;
    }

}

你可能感兴趣的:(缓存,-,Redis)