springboot分布式锁

分布式锁工具类
import com.cesec.common.enums.ResultEnum;
import com.cesec.common.exception.BizException;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * @Title 分布式锁工具类
 * @Date 2019-12-03
 * @Version V1.0
 * @Description
 */
@Component
public class DistributeLockUtils {

    /**
     * 注入 SpringBoot 框架自动生成的 StringRedisTemplate
     */
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 获取分布式锁,成功返回 true,失败返回 false
     * @param lockKey 分布式锁的key
     * @param lockKeyId 分布式锁标识
     * @param timeout 分布式锁的超时时间
     * @return
     */
    public boolean lock(String lockKey, String lockKeyId, long timeout){
        return stringRedisTemplate.opsForValue().setIfAbsent(lockKey, lockKeyId, timeout, TimeUnit.SECONDS);
    }

    /**
     * 释放分布式锁
     * @param lockKey 分布式锁的key
     * @param lockKeyId 分布式锁标识
     * @return
     */
    public boolean unLock(String lockKey, String lockKeyId) {
        // 防止删除其他请求线程的锁
        if (lockKeyId.equals(stringRedisTemplate.opsForValue().get(lockKey))) {
            // 释放锁
            Boolean deleteFlag = stringRedisTemplate.delete(lockKey);
            System.out.println("锁释放成功标志 " + " [" + Thread.currentThread().getName() + "]");
            return deleteFlag;
        }
        return false;
    }

    /**
     * 校验是否获取分布式锁
     * @param flag
     */
    public void checkLock(boolean flag) {
        // 获取分布式锁失败,当前锁正在被占用,抛出系统繁忙异常
        CheckUtils.checkArgument(flag, ResultEnum.SYSTEM_BUSY);
    }


    /**
     * 延长分布式锁的过期时间,异步调用
     * @param lockKey
     */
    @Async("taskExecutor")
    public void extendExpTime(String lockKey, final long timeout) {
        try {
            while (true) {
                // 1.无论锁是否存在,先重置锁的失效时间
                stringRedisTemplate.expire(lockKey, timeout, TimeUnit.SECONDS);
                System.out.println("锁延长:" + timeout + "s [" + Thread.currentThread().getName() + "]");

                // 2.判断锁是否存在,主线程释放锁后锁就不存在了,用于终止异步线程,使其弹栈
                String lockKeyId = stringRedisTemplate.opsForValue().get(lockKey);
                if (StringUtils.isEmpty(lockKeyId)) {
                    return;
                }

                // 3.设置时间间隔,即多久重置一次锁的时间,时间间隔一般是锁过期时间的 1 / 3
                long timeInterval = timeout / 3 == 0 ? 1 : timeout / 3;
                Thread.sleep(timeInterval * 1000);
            }
        } catch (Exception e) {
            throw new BizException(ResultEnum.SYSTEM_ERROR);
        }
    }

}
springboot 分布式锁的实现代码
// 1.分布式锁唯一标识,采用UUID
String lockKeyId = UUID.randomUUID().toString();

// 2.获取锁,设置锁标识
long timeout = 5L;
boolean flag = distributeLockUtils.lock(productId, lockKeyId, timeout);

// 3.延长锁失效时间
distributeLockUtils.extendExpTime(productId, timeout);

// 4.判断锁是否有效
distributeLockUtils.checkLock(flag);

// 5.获取锁成功后,执行业务代码
// 业务代码开始执行标志
System.out.println("request start " + "[" + Thread.currentThread().getName() + "]");

try { //业务代码
	**************************
	**************************
	**************************
    // 测试:
    // 模拟业务代码处理时间为 10s,但是将锁超时时间设置为 5 秒,
    // 即模拟在业务代码还没有执行完时锁失效,第二个请求线程进来时的场景
    try {
        Thread.sleep(10000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    // 业务代码运行结束标志
    System.out.println("request end" + " [" + Thread.currentThread().getName() + "]");
} finally {
    // 6.释放锁
    distributeLockUtils.unLock(productId, lockKeyId);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值