redis实现分布式线程锁

配置pom文件

 配置Bean

@Bean
    public DefaultRedisScript<Long> defaultRedisScript() {
        DefaultRedisScript<Long> defaultRedisScript = new DefaultRedisScript<>();
        defaultRedisScript.setResultType(Long.class);
        defaultRedisScript.setScriptText("if redis.call('get', KEYS[1]) == KEYS[2] then return redis.call('del', KEYS[1]) else return 0 end");
        return defaultRedisScript;
    }

写一个获取线程锁和解锁的工具类

@Slf4j
@Component
public class Lock {
    @Autowired
    private StringRedisTemplate redisTemplate;

    public Boolean lockEnable(String key, long expire) {

        //这是将当前线程的名字置为key的value值,表明该锁被谁拿到
        String keyValue = Thread.currentThread().getName();

        //1,这是StringRedisTemplate在set key的同时增加了过期时间,防止死锁。保证了原子性。
        //2,setIfAbsent该方法如果该key不存在时候,设置值进去后,返回true;若是已经存在,则返回false;
        Boolean aBoolean = redisTemplate.opsForValue().setIfAbsent(key, keyValue, expire, TimeUnit.SECONDS);
        Long surplusTime = redisTemplate.getExpire(key, TimeUnit.SECONDS);
        if (!aBoolean) {
            log.info("该线程【{}】加锁失败,该key【{}】剩余过期时间【{}】秒", keyValue, key, surplusTime);
            return false;
        }
        log.info("该线程【{}】加锁成功,该key【{}】剩余过期时间【{}】秒", keyValue, key, surplusTime);
        return true;
    }

    @Autowired
    private DefaultRedisScript<Long> redisScript;

    public Boolean lockUnable(String key) {
        String keyValue = Thread.currentThread().getName();
        //key和value不一致时,返回:【0】
        //key和value一致时,返回:【1】
        Long execute = redisTemplate.execute(redisScript, Arrays.asList(key, keyValue));
        if(execute != 1 ){
            Boolean aBoolean = redisTemplate.hasKey(key);
            Long surplusTime = redisTemplate.getExpire(key, TimeUnit.SECONDS);
            log.info("该key【{}】解锁失败,是否存在【{}】,剩余过期时间【{}】秒", key, aBoolean, surplusTime);
            return false;
        }
        log.info("该key【{}】解锁成功", key);
        Boolean aBoolean = redisTemplate.hasKey(key);
        log.info("该key是否存在【{}】",aBoolean);
        return true;
    }
}

在测试单元多线程调用

@Test
    public void catchData() {
        for (int i = 0; i <100; i++) {
            Thread thread = new Thread(() -> {
                threadTest();
            });
            thread.start();
            thread.setName("thread" + i);
        }
        while (true){

        }
    }
    void threadTest(){
        Boolean aBoolean = lock.lockEnable("秒杀", 600);


        if (!aBoolean) {
            log.info("线程【{}】没有拿到锁,结束流程",Thread.currentThread().getName());
            return;
        }
        
        log.info("线程【{}】更新数据成功",Thread.currentThread().getName());


        /**
         * 释放该条数据的锁
         */
        Boolean aBoolean1 = lock.lockUnable("狄仁杰");
        log.info("线程【{}】是否成功释放锁:【{}】",Thread.currentThread().getName(),aBoolean1);
    }

运行看效果

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值