虫虫blog html教程,虫虫的成长历程

本文讨论了Redis在分布式锁实现中的两种不成熟方案及其存在的并发问题,随后介绍了较为认可的解决方案,即利用Setnx结合过期时间戳确保锁的安全性。然而,这种方法仍存在疑问点,包括过期时间判断的风险、释放锁的正确性以及宕机对锁的影响。文章提出了对Redis锁安全性的深入思考,并强调了理解复杂并发执行顺序的重要性。
摘要由CSDN通过智能技术生成

我们在分布式场景下,需要用到分布式锁,分布式锁的实现方案可以有redis实现,zk实现等,这里只讨论redis的方案

先稍微铺垫一下两个redis的不成熟方案,

一,

Get,判断是否存在,如存在直接返回失败,不存在继续

Set,设置锁,key对应的value为1,并设置过期时间

Del,业务执行完毕释放锁

code如下:

private static long expireTime = 20000;

public static boolean getLock(String key) {

String lock = RedisUtil.get(key);

if (!"1".equals(lock)) {

RedisUtil.set(key, "1");

RedisUtil.expire(key, expireTime);

return true;

} else {

return false;

}

}

public static void releaseLock(String key) {

String check = RedisUtil.get(key);

if (check != null) {

RedisUtil.del(key);

}

}

此方案明显存在的问题就是,多个线程同时请求get,不存在,同时set,所以会有多个线程进入的可能

二,

Setnx,key对应的value为1,判断返回结果,0为设置失败,已经存在key,直接返回失败,1设置成功,继续

Expire,设置过期时间

Del,业务执行完毕释放锁

code如下:

private static long expireTime = 20000;

public static boolean getLock(String key) {

long lock = RedisUtil.setNX(key, "1");

if (lock == 1) {

RedisUtil.expire(key, expireTime);

return true;

} else {

return false;

}

}

public static void releaseLock(String key) {

String check = RedisUtil.get(key);

if (check != null) {

RedisUtil.del(key);

}

}

此方法,如果在setnx后expire前宕机,那key就不会被删除也没有过期,别的线程永远也进不来了

然后说下目前同事用到的,以及网上找到的比较被认可的解决方案

Setnx,key对应的value为过期时间戳,判断设置结果,1设置成功,返回成功,0设置失败,key存在内容,继续

Get,取出key的值,判断过期,如没过期,返回失败,如已过期,或者key已经不存在了,继续

Getset,设置锁,同时拿到返回值为设置之前的值,判断是否与刚才取出的值相等,如相等,证明是自己设置的,返回成功,如不相等,证明不是自己设置的,返回失败

Del,业务执行完毕释放锁

code如下:

private static long expireTime = 20000;

public static boolean getLock(String key) {

long lock = RedisUtil.setNX(key, "" + System.currentTimeMillis() + expireTime);

if (lock == 1) {

return true;

} else {

String check = RedisUtil.get(key);

if (check != null && System.currentTimeMillis() < Long.valueOf(check)) {

//key还没有过期

return false;

} else {

//key过期或者已经不存在了

String old = RedisUtil.getSET(key, "" + System.currentTimeMillis() + expireTime);

if (old == null) {

//说明此时已经key已经不存在,获取锁成功

return true;

} else {

// TODO 疑问点1,这里同事用的是否过期的判断,会不会存在风险?

if (check.equals(old)) {

//获取锁成功

return true;

} else {

//在getSET之  前已经被别的线程获取了锁,获取锁失败

return false;

}

}

}

}

}

public static void releaseLock(String key) {

String check = RedisUtil.get(key);

if (check != null) {

if (System.currentTimeMillis() < Long.valueOf(check)) {

// TODO 疑问点2,有没有可能删除别的线程设置的key

RedisUtil.del(key);

} else {

// TODO 疑问点3,过期了是否需要删除

}

} else {

}

}

// TODO 疑问点4,expire正常来说是需要设置成一个业务一定在此时间内能执行完成的时间,那么,业务如果万一没有执行完成的时候,redis锁还安全么?

// TODO 疑问点5,redis锁真的安全吗,多个线程错综复杂的执行顺序,如何能比较好的理解呢?

// TODO 疑问点6,这里还有个疑问,是不是理论上每两行代码之间都可能会中断,比如宕机,比如卡死过了很长时间之后继续执行?这个疑问明显的体现出了基础的薄弱

由于没有找到合适的人讨论,所以这里暂时把自己的疑问记录下来,待以后有机会再理解透彻

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值