自己做网站需要什么技能,做期货在哪个网站看消息,搜索app下载安装,做的比较好的网站推荐线程1现在持有锁之后#xff0c;在执行业务逻辑过程中#xff0c;他正准备删除锁#xff0c;而且已经走到了条件判断的过程中#xff0c;比如他已经拿到了当前这把锁确实是属于他自己的#xff0c;正准备删除锁#xff0c;但是此时他的锁到期了#xff0c;那么此时线程2…线程1现在持有锁之后在执行业务逻辑过程中他正准备删除锁而且已经走到了条件判断的过程中比如他已经拿到了当前这把锁确实是属于他自己的正准备删除锁但是此时他的锁到期了那么此时线程2进来但是线程1他会接着往后执行当他卡顿结束后他直接就会执行删除锁那行代码相当于条件判断并没有起到作用这就是删锁时的原子性问题之所以有这个问题是因为线程1的拿锁比锁删锁实际上并不是原子性的我们要防止刚才的情况发生 Redis提供了Lua脚本功能在一个脚本中编写多条Redis命令确保多条命令执行时的原子性。Lua是一种编程语言它的基本语法大家可以参考网站https://www.runoob.com/lua/lua-tutorial.html这里重点介绍Redis提供的调用函数我们可以使用lua去操作redis又能保证他的原子性这样就可以实现拿锁比锁删锁是一个原子性动作了作为Java程序员这一块并不作一个简单要求并不需要大家过于精通只需要知道他有什么作用即可。 接下来就是我们之前释放锁的逻辑 释放锁的业务流程是这样的
1、获取锁中的线程标示
2、判断是否与指定的标示当前线程标示一致
3、如果一致则释放锁删除
4、如果不一致则什么都不做
如果用Lua脚本来表示则是这样的
最终我们操作redis的拿锁比锁删锁的lua脚本就会变成这样
-- 这里的 KEYS[1] 就是锁的key这里的ARGV[1] 就是当前线程标示
-- 获取锁中的标示判断是否与当前线程标示一致
if (redis.call(GET, KEYS[1]) ARGV[1]) then-- 一致则删除锁return redis.call(DEL, KEYS[1])
end
-- 不一致则直接返回
return 0下面就是在java中如何调用我们的RedisTemplate中可以利用execute方法去执行lua脚本。 Java代码
private static final DefaultRedisScriptLong UNLOCK_SCRIPT;static {UNLOCK_SCRIPT new DefaultRedisScript();UNLOCK_SCRIPT.setLocation(new ClassPathResource(unlock.lua));UNLOCK_SCRIPT.setResultType(Long.class);}Overridepublic void unLock() {// 调用lua脚本stringRedisTemplate.execute(UNLOCK_SCRIPT,Collections.singletonList(KEY_PREFIX name),Collections.singletonList(ID_PREFIX Thread.currentThread().getId()));}小总结
基于Redis的分布式锁实现思路
利用set nx ex获取锁并设置过期时间保存线程标示释放锁时先判断线程标示是否与自己一致一致则删除锁 特性 利用set nx满足互斥性利用set ex保证故障时锁依然能释放避免死锁提高安全性利用Redis集群保证高可用和高并发特性
测试逻辑 第一个线程进来得到了锁手动删除锁模拟锁超时了其他线程会执行lua来抢锁当第一天线程利用lua删除锁时lua能保证他不能删除他的锁第二个线程删除锁时利用lua同样可以保证不会删除别人的锁同时还能保证原子性。