redis实现分布式锁

2 篇文章 0 订阅
定义锁对象
package com.tinet.clink.core.lock;

import java.io.Closeable;
import java.util.UUID;

/**
 * 通过Redis实现的分布式锁
 *
 * @author Dengsx
 * @date 2018/05/11
 */
public class RedisLock implements Closeable {
    private String key;
    private final UUID uuid;
    private long lockTimeout;
    private RedisLockService redisLockService;

    public RedisLock(String key, UUID uuid, long lockTimeout, RedisLockService redisLockService) {
        this.key = key;
        this.uuid = uuid;
        this.lockTimeout = lockTimeout;
        this.redisLockService = redisLockService;
    }

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public UUID getUuid() {
        return uuid;
    }

    public long getLockTimeout() {
        return lockTimeout;
    }

    public void setLockTimeout(long lockTimeout) {
        this.lockTimeout = lockTimeout;
    }

    @Override
    public void close() {
        this.redisLockService.unLock(this);
    }
}


分布式锁服务
package com.tinet.clink.core.lock;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;

import java.util.Collections;
import java.util.UUID;

/**
 * Redis分布式锁服务
 *
 * @author Dengsx
 * @date 2018/05/11
 */
public class RedisLockService {
    private Logger logger = LoggerFactory.getLogger(getClass());
    private static final long DEFAULT_LOCK_TIME_OUT = 3000; // 锁的过期时间,单位毫秒
    private static final long DEFAULT_TRY_LOCK_TIME_OUT = 0;// 争抢锁的超时时间,单位毫秒,0代表永不超时(一直抢到锁为止)
    private static final String LUA_SCRIPT_LOCK = "return redis.call('SET', KEYS[1], ARGV[1], 'NX', 'PX', ARGV[2]) ";
    private static final String LUA_SCRIPT_UNLOCK = "if (redis.call('GET', KEYS[1]) == ARGV[1]) then return redis" +
            ".call('DEL',KEYS[1]) else return 0 end";
    private static RedisScript<String> scriptLock = new DefaultRedisScript<String>(LUA_SCRIPT_LOCK, String.class);
    private static RedisScript<String> scriptUnlock = new DefaultRedisScript<String>(LUA_SCRIPT_UNLOCK, String.class);
    private RedisTemplate<String, Object> redisTemplate;

    public RedisLockService(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    /**
     * 获取锁
     *
     * @param key 锁的标识键
     * @return 如果获取锁成功,返回RedisLock对象,否则返回null
     */
    public RedisLock lock(String key) {
        return lock(key, DEFAULT_LOCK_TIME_OUT, DEFAULT_TRY_LOCK_TIME_OUT);
    }

    /**
     * 获取锁,指定锁过期时间
     *
     * @param key         锁的标识键
     * @param lockTimeout 锁的过期时间,单位毫秒
     * @return 如果获取锁成功,返回RedisLock对象,否则返回null
     */
    public RedisLock lock(String key, long lockTimeout) {
        return lock(key, lockTimeout, DEFAULT_TRY_LOCK_TIME_OUT);
    }

    /**
     * 获取锁,指定锁过期时间/争抢锁超时时间
     *
     * @param key            锁的标识键
     * @param lockTimeout    锁的过期时间,单位毫秒
     * @param tryLockTimeout 争抢锁的超时时间,单位毫秒,0代表永不超时(一直抢到锁为止)
     * @return 如果获取锁成功,返回RedisLock对象,否则返回null
     */
    public RedisLock lock(String key, long lockTimeout, long tryLockTimeout) {
        key = key + ".lock";
        long timestamp = System.currentTimeMillis();
        UUID uuid = UUID.randomUUID();
        while (tryLockTimeout == 0 || (System.currentTimeMillis() - timestamp) < tryLockTimeout) {
            String result = redisTemplate.execute(scriptLock, redisTemplate.getStringSerializer(),
                    redisTemplate.getStringSerializer(), Collections.singletonList(key), uuid.toString(),
                    String.valueOf(lockTimeout));
            if (result != null && result.equals("OK")) {
                logger.debug("获取锁成功:" + key);
                return new RedisLock(key, uuid, lockTimeout, this);
            } else {
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    logger.error(e.toString(), e);
                }
            }
        }

        logger.debug("获取锁失败:" + key);
        return null;
    }

    /**
     * 尝试获取锁,获取失败则立即返回null,不等待。使用默认的锁过期时间。
     *
     * @param key
     * @return
     */
    public RedisLock lockWithoutWait(String key) {
        return lockWithoutWait(key, DEFAULT_LOCK_TIME_OUT);
    }

    /**
     * 尝试获取锁,获取失败则立即返回null,不等待
     *
     * @param key
     * @param lockTimeout 锁的过期时间,单位毫秒
     * @return
     */
    public RedisLock lockWithoutWait(String key, long lockTimeout) {
        key = key + ".lock";
        UUID uuid = UUID.randomUUID();

        String result = redisTemplate.execute(scriptLock, redisTemplate.getStringSerializer(),
                redisTemplate.getStringSerializer(), Collections.singletonList(key), uuid.toString(),
                String.valueOf(lockTimeout));
        if (result != null && result.equals("OK")) {
            logger.debug("获取锁成功:" + key);
            return new RedisLock(key, uuid, lockTimeout, this);
        }

        logger.debug("获取锁失败:" + key);
        return null;
    }

    /**
     * 释放锁
     *
     * @param lock RedisLock对象
     */
    public void unLock(RedisLock lock) {
        if (lock == null) {
            return;
        }

        redisTemplate.execute(scriptUnlock, redisTemplate.getStringSerializer(), redisTemplate.getStringSerializer(),
                Collections.singletonList(lock.getKey()), lock.getUuid().toString());
        logger.debug("释放锁成功:" + lock.getKey());
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值