当前位置: 首页 > wzjs >正文

西安网站建设 早晨嵌入式开发工资

西安网站建设 早晨,嵌入式开发工资,丛台企业做网站推广,美工常用找素材网站基于redis的分布式锁 lua脚本解决原子性 之前我们实现的乐观锁和悲观锁来控制超卖有一定效果,但它们都只能在单机环境下生效。在分布式系统中,我们需要更强大的锁机制来确保跨多个服务实例的数据一致性。Redisson是一个在Redis基础上实现的Java分布式服务…

基于redis的分布式锁 lua脚本解决原子性

之前我们实现的乐观锁和悲观锁来控制超卖有一定效果,但它们都只能在单机环境下生效。在分布式系统中,我们需要更强大的锁机制来确保跨多个服务实例的数据一致性。Redisson是一个在Redis基础上实现的Java分布式服务,它提供了强大的分布式锁实现,可以帮助我们解决分布式环境下的并发控制问题。

分布式锁:满足分布式系统或集群模式下多进程可见并且互斥的锁

分布式锁的核心思想就是让大家都使用同一把锁,只要大家使用的是同一把锁,那么我们就能锁住线程,不让线程进行,让程序串行执行,这就是分布式锁的核心思路

事实上我们有很多实现分布式锁的方法 但redis优势更大一些 接下来我们用redis来实现一下分布式锁

主要分两步

  • 获取锁:
    • 互斥:确保只能有一个线程获取锁
    • 非阻塞:尝试一次,成功返回true,失败返回false
  • 释放锁:
    • 手动释放
    • 超时释放:获取锁时添加一个超时时间

我们利用redis 的setNx 方法,当有多个线程进入时,我们就利用该方法,第一个线程进入时,redis 中就有这个key 了,返回了1,如果结果是1,则表示他抢到了锁,那么他去执行业务,然后再删除锁,退出锁逻辑,没有抢到锁的哥们,等待一定时间后重试即可

public class SimpleRedisLock implements ILock{//不同的业务应该有不同的所private String name;private StringRedisTemplate stringRedisTemplate;//给锁加一个前缀private static final String KEY_PREFIX="lock:";//接收用户传递给我们的参数public SimpleRedisLock(String name, StringRedisTemplate stringRedisTemplate) {this.name = name;this.stringRedisTemplate = stringRedisTemplate;}/*** 尝试获取锁** @param timeoutSec* @return*/@Overridepublic boolean tryLock(long timeoutSec) {//获取线程标识long thresdId = Thread.currentThread().getId();//获取锁——如果不存在才执行:nxBoolean success = stringRedisTemplate.opsForValue().setIfAbsent(KEY_PREFIX+name,threadId+"", timeoutSec, TimeUnit.SECONDS);/*** 若success是true,这里返回true* 若sucess是false,这里返回false* 若这里为空,返回的也是false* 避免空指针异常*/return Boolean.TRUE.equals(success);}/*** 释放锁*/@Overridepublic void unlock() {stringRedisTemplate.delete(KEY_PREFIX+name);}
}
//足够,创建订单Long userId = UserHolder.getUser().getId();//创建锁对象SimpleRedisLock lock = new SimpleRedisLock("order" + userId, stringRedisTemplate);//获取锁boolean isLock = lock.tryLock(1200);//判断是否获取锁成功if (!isLock) {//获取锁失败,返回错误return Result.fail("不允许重复下单!");}try {//获取代理对象(事务)IVoucherOrderService proxy= (IVoucherOrderService) AopContext.currentProxy();return proxy.createVoucherOrder(voucherId);} finally {//释放锁lock.unlock();}

这样我们在测试的时候就会发现 我们虽然部署两台tomcat服务器 但锁不仅仅是在一个jvm中的 而是作用域全局的

但还有一些问题 例如 持有锁的线程在锁的内部出现了阻塞,导致他的锁自动释放,这时其他线程,线程2来尝试获得锁,就拿到了这把锁,然后线程2在持有锁执行过程中,线程1反应过来,继续执行,而线程1执行过程中,走到了删除锁逻辑,此时就会把本应该属于线程2的锁进行删除,这就是误删别人锁的情况说明

解决起来也很简单 解决方案就是在每个线程释放锁的时候,去判断一下当前这把锁是否属于自己,如果属于自己,则不进行锁的删除,假设还是上边的情况,线程1卡顿,锁自动释放,线程2进入到锁的内部执行逻辑,此时线程1反应过来,然后删除锁,但是线程1,一看当前这把锁不是属于自己,于是不进行删除锁逻辑,当线程2走到删除锁逻辑时,如果没有卡过自动释放锁的时间点,则判断当前这把锁是属于自己的,于是删除这把锁。(是不是很像版本号法解决)

  1. 修改之前的分布式锁实现,满足:在获取锁时存入线程标示(可以用UUID表示)
    在释放锁时先获取锁中的线程标示,判断是否与当前线程标示一致
  2. 如果一致则释放锁 如果不一致则不释放锁
    核心逻辑:在存入锁时,放入自己线程的标识,在删除锁时,判断当前这把锁的标识是不是自己存入的,如果是,则进行删除,如果不是,则不进行删除。
    /*** 释放锁*/@Overridepublic void unlock() {//获取线程标识String thresdId = ID_PREFIX+Thread.currentThread().getId();//获取锁中的标识String id = stringRedisTemplate.opsForValue().get(KEY_PREFIX + name);//判断标识是否一致if (threadId.equals(id)) {stringRedisTemplate.delete(KEY_PREFIX+name);}}

这样就解决我们刚刚的问题了

假设还有更极端的一种情况

线程1现在持有锁之后,在执行业务逻辑过程中,他正准备删除锁,而且已经走到了条件判断的过程中,比如他已经拿到了当前这把锁确实是属于他自己的,正准备删除锁,但是此时他的锁到期了,那么此时线程2进来,但是线程1他会接着往后执行,当他卡顿结束后,他直接就会执行删除锁那行代码,相当于条件判断并没有起到作用,这就是删锁时的原子性问题,之所以有这个问题,是因为线程1的拿锁,比锁,删锁,实际上并不是原子性的,我们要防止刚才的情况发生

就需要lua登场了 lua是一种脚本语言 Redis提供了Lua脚本功能,在一个脚本中编写多条Redis命令,确保多条命令执行时的原子性。这里重点介绍Redis提供的调用函数,我们可以使用lua去操作redis,又能保证他的原子性,这样就可以实现拿锁比锁删锁是一个原子性动作了

这里重点介绍Redis提供的调用函数,语法如下:

redis.call('命令名称', 'key', '其它参数', ...)
# 先执行 set name jack
redis.call('set', 'name', 'Rose')
# 再执行 get name
local name = redis.call('get', 'name')
# 返回
return name

如果脚本中的key、value不想写死,可以作为参数传递。key类型参数会放入KEYS数组,其它参数会放入ARGV数组,在脚本中可以从KEYS和ARGV数组获取这些参数:

EVAL "return redis.call('set',KEYS[1],ARGV[1])" 1 name tom

因此我们可以改造一下 我们希望最后两步保证原子性 因此只需要把最后两步写入lua脚本 执行即可

-- 比较线程标示与锁中的标示是否一致
if(redis.call('get', KEYS[1]) ==  ARGV[1]) then-- 释放锁 del keyreturn redis.call('del', KEYS[1])
end
return 0
private static final DefaultRedisScript<Long> UNLOCK_SCRIPT;static {UNLOCK_SCRIPT = new DefaultRedisScript<>();UNLOCK_SCRIPT.setLocation(new ClassPathResource("unlock.lua"));UNLOCK_SCRIPT.setResultType(Long.class);}public void unlock() {// 调用lua脚本stringRedisTemplate.execute(UNLOCK_SCRIPT,Collections.singletonList(KEY_PREFIX + name),ID_PREFIX + Thread.currentThread().getId());
}

基于Redis的分布式锁实现思路:

  • 利用set nx ex获取锁,并设置过期时间,保存线程标示
  • 释放锁时先判断线程标示是否与自己一致,一致则删除锁
    • 特性:
      • 利用set nx满足互斥性
      • 利用set ex保证故障时锁依然能释放,避免死锁,提高安全性
      • 利用Redis集群保证高可用和高并发特性

文章转载自:

http://KG4EVTl9.wnqfz.cn
http://dFjO6uhm.wnqfz.cn
http://RdyOS9zQ.wnqfz.cn
http://zSt2N4Ra.wnqfz.cn
http://oXW8QIse.wnqfz.cn
http://g299ZiNX.wnqfz.cn
http://UdN8Qqrq.wnqfz.cn
http://BHnjysaF.wnqfz.cn
http://eYk6bSY0.wnqfz.cn
http://Xu9FCOMl.wnqfz.cn
http://7CZGwEct.wnqfz.cn
http://G9eusMhQ.wnqfz.cn
http://GhM34wBT.wnqfz.cn
http://77K2UcJv.wnqfz.cn
http://zBZvDQ6U.wnqfz.cn
http://pGVg7FCo.wnqfz.cn
http://BwazRhtr.wnqfz.cn
http://taIExsnu.wnqfz.cn
http://CUbD1kMI.wnqfz.cn
http://eJAaFDVT.wnqfz.cn
http://XIHpP3WJ.wnqfz.cn
http://GoHtLCp8.wnqfz.cn
http://0ruCv9cl.wnqfz.cn
http://HtZhAEnV.wnqfz.cn
http://CeRfvgUH.wnqfz.cn
http://BRDAPZNv.wnqfz.cn
http://bnC04l1k.wnqfz.cn
http://f3FrIZTn.wnqfz.cn
http://2V2Nhx1Z.wnqfz.cn
http://4qHaP5cC.wnqfz.cn
http://www.dtcms.com/wzjs/734037.html

相关文章:

  • 动易网站做值班表怎么创作一个微信小程序
  • 哪些网站适合瀑布流电商网站建设与维护试题
  • 电商建设网站公众号推送怎么制作
  • 福州 福马路 网站建设个体可以做几个网站
  • 推荐手机网址唐山seo优化
  • 四川城乡住房城乡建设厅网站ps软件是干什么用的
  • 台州超值营销型网站建设地址门户网站是指
  • 牙科医院网站开发做网站多少钱 网络服务
  • 网站的导航栏专业的网站开发建设
  • 青岛建站方案wordpress 调整布局
  • 免费的建筑设计网站项目经理证书
  • 公司网站制作需要多少钱上海长城建设有限公司网站
  • 网站外链购买青岛微网站开发
  • 网站诚信认证电话销售中国工业品网
  • 律师网站建设哪家专业惠州seo关键字优化
  • 计算机基础网站建设和网络安全国产crm系统91
  • 重庆模板自助建站整合营销传播经典案例
  • 深圳做网站公司多少钱洛可可设计公司待遇
  • 网站图片展示方式网站建设qinnet
  • 网站做游戏活动铜陵网站制作
  • 建设银行企业网上银行网站做设计_素材网站有哪
  • 钓鱼网站在线生成杭州营销型网站怎么做
  • 餐饮营销网站建设龙华在深圳算什么档次
  • 为什么需要响应式网站天津网上办事大厅官网
  • 自己做网站网页文件在哪里wordpress 查询文章
  • 网站开发需要看哪些书网页无法访问此页面
  • 用博客做网站长沙谷歌seo
  • 横岗网站建设大渡口网站建设
  • 网站建设策划案深圳做响应式网站
  • 怎么判断网站开发语言app开发公司比较好