简单适用基于redis的分布式锁

public class Lock {

    private static final ThreadLocal<Long> threadLocal = new ThreadLocal<>();

    private StringRedisTemplate stringRedisTemplate;

    @Value("${lock.ttl: 3000}")
    private long lockTTL;
    @Value("${lock.wait: 3000}")
    private long lockWait;

    public Lock(StringRedisTemplate stringRedisTemplate) {
        this.stringRedisTemplate = stringRedisTemplate;
    }

    public boolean lockWait(String lockKey){
        return lockWait(lockKey, lockWait);
    }

    public boolean lockWait(String lockKey, long lockWaitMillSec) {

        log.info("尝试获取锁{}, {}", lockKey, lockWaitMillSec);
        long start = System.currentTimeMillis();
        while(!lock(lockKey)) {
            try {
                long current = System.currentTimeMillis();
                if(current - start > lockWaitMillSec) {
                    log.warn("获取锁{}超时{}", lockKey, lockWaitMillSec);
                    return false;
                }
                Thread.sleep(100);
            } catch (InterruptedException e) {
                log.error("等待获得锁异常", e);
            }
        }
        log.info("成功获取到锁{}", lockKey);
        return true;
    }

    boolean lock(String key) {
        return lock(key, lockTTL);
    }

    boolean lock(String key, long lockTTLMillSec) {
        String lockKey = lockKey(key);
        ValueOperations<String, String> valueOperations = stringRedisTemplate.opsForValue();

        long expireAt = System.currentTimeMillis() + lockTTLMillSec;

        boolean acquired;
        if(acquired = valueOperations.setIfAbsent(lockKey, String.valueOf(expireAt))) {
            threadLocal.set(expireAt);
        } else {
            String expiredTimeOldValue = valueOperations.get(lockKey);
            if (expiredTimeOldValue != null) {
                // 锁已超时
                if (Long.valueOf(expiredTimeOldValue) < System.currentTimeMillis()) {
                    String oldValue = valueOperations.getAndSet(lockKey, String.valueOf(expireAt));
                    // 防止其它线程先获得了锁状态.
                    if(StringUtils.equals(oldValue, expiredTimeOldValue)) {
                        log.info("解锁超时锁并重新获得锁 {}:{} => {}", lockKey, expiredTimeOldValue, expireAt);
                        threadLocal.set(expireAt);
                        return true;
                    }
                }
            }
        }
        return acquired;
    }

    public void unlock(String key) {

        log.info("释放锁{}", key);

        // 可能在未获取到锁的情况下调用
        if(threadLocal.get() == null) {
            return;
        }

        String lockKey = lockKey(key);
        Object expiredTimeAt = stringRedisTemplate.opsForValue().get(lockKey);
        if(expiredTimeAt != null) {
            long currentTime = System.currentTimeMillis();
            // redis锁未超时, 并且 当前持有锁的任务没超时
            if(Long.valueOf(expiredTimeAt.toString()) > currentTime && threadLocal.get() > currentTime) {
                stringRedisTemplate.delete(lockKey);
            }
        }
        threadLocal.remove();
    }

    String lockKey(String key){
        return String.format("%s~lock", key);
    }
}

工具基于spring框架的StringRedisTemplate,需要spring框架支持,当然也可以自己基于其它方式实现redis操作

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值