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

淘宝客登记新网站郑州经济技术开发区协同办公系统

淘宝客登记新网站,郑州经济技术开发区协同办公系统,网站建站的类型,新华网海南频道一、什么是分布式锁 我们在上篇文章中实现了单机模式下的秒杀业务。其中采用了synchronized加锁来解决各种线程安全问题。而synchronized关键字是依赖于单机的JVM#xff0c;在集群模式下#xff0c;每个服务器都有独立的JVM#xff0c;如果此时还采用synchronized关键字加… 一、什么是分布式锁 我们在上篇文章中实现了单机模式下的秒杀业务。其中采用了synchronized加锁来解决各种线程安全问题。而synchronized关键字是依赖于单机的JVM在集群模式下每个服务器都有独立的JVM如果此时还采用synchronized关键字加锁就会导致不同服务器间出现线程安全问题 这时我们就需要一个不依赖JVM的独立的锁去统一地对多台服务器进行加锁操作 像这样独立出来的锁就被称之为分布式锁。 一个优秀的分布式锁需要满足以下特性 多进程可见互斥高可用高性能安全性…… 二、分布式锁的实现 分布式锁的核心是实现多进程之间的互斥常见的有三种实现方式 相比之下redis在性能上是最好的本篇文章就主要来探讨用redis来实现一个分布式锁。 Redis实现简单的分布式锁 这里的锁最重要的一个特点就是需要具备互斥性。redis中的setnx操作在key不存在的时候可以写入key如果存在就将无法写入就很符合互斥性的特点。 这样我们就可以尝试用setnx操作来自己实现一个互斥锁SimpleRedisLock  加锁时会执行setnx操作向Redis中添加锁信息。由于setnx的互斥性只有第一个执行setnx操作的线程才能成功执行写入操作并返回成功信息则表示着加锁成功此时其它线程尝试获取锁去执行setnx操作就会失败返回错误信息则表示加锁失败进入阻塞等待。这样就实现了一个简单的锁的功能。 同时为了避免某个线程在获取锁后执行时间过长导致大量线程长时间处于阻塞态甚至出现死锁问题。因此我们可以通过Redis的expire操作对锁添加过期时间 代码实现 public class SimpleRedisLock implements ILock{//锁的名称private String name;//传入redis的方法private StringRedisTemplate stringRedisTemplate;public SimpleRedisLock(String name, StringRedisTemplate stringRedisTemplate) {this.namename;this.stringRedisTemplatestringRedisTemplate;}//锁的前缀private static final String KEY_PREFIXlock:;Overridepublic boolean tryLock(long timeoutSec) {//获取线程标识long threadId Thread.currentThread().getId();//尝试获取锁Boolean success stringRedisTemplate.opsForValue().setIfAbsent(KEY_PREFIX name, threadId , timeoutSec, TimeUnit.SECONDS);//判断获取锁是否成功return Boolean.TRUE.equals(success);}Overridepublic void unlock() {//释放锁即删除redis中对应的锁对象stringRedisTemplate.delete(KEY_PREFIXname);} }运行流程 接着就可以用它来代替synchronized为我们上篇文章中的代码进行加锁操作了 Long userId UserHolder.getUser().getId();//创建锁对象SimpleRedisLock locknew SimpleRedisLock(order:userId,new StringRedisTemplate());//尝试获取锁boolean isLock lock.tryLock(1200);//判断获取锁是否成功if(!isLock){//获取锁失败返回错误或重试return Result.fail(不许重复下单);}try{//获取当前对象的代理对象IVoucherOrderService proxy (IVoucherOrderService)AopContext.currentProxy();return proxy.createVoucherOrder(voucherId);}finally {lock.unlock();} 误删问题 但是上述实现的锁在一些情况下是存在问题的 由于我们为分布式锁设置了过期时间很有可能会出现 线程一 业务还未执行完二锁却因为超时而被释放的情况。由于锁被释放这时其它线程比如 线程二 就会抢到锁并在Redis中存储上新的锁标识开始执行自己的业务逻辑。期间 线程一 可能才执行完业务逻辑并按照流程进行释放锁的操作此时它并不知道Redis中存储的锁已经不是自己那把了依旧会删除掉Redis中的锁。而此时 线程二 的业务也没有完成但锁却被删掉了此时其它线程如 线程三 又会抢到锁也有可能会被 线程二 误删掉锁以此类推。 这种现象就被称之为误删问题。 我们可以通过在对锁进行删除操作前加上判断判断此时Redis中存储的锁标识是否与自己的锁标识一致。若一致则正常执行删除操作若不一致则不进行删除。 这样就可以对代码进行改进 在加锁时存入线程标识。由于不同服务器的线程id可能会发生重复所以我们可以生成随机的UUID作为前缀保证线程标识的唯一性 private static final String ID_PREFIX UUID.randomUUID().toString(true) -;Overridepublic boolean tryLock(long timeoutSec) {// 获取线程标识String threadId ID_PREFIXThread.currentThread().getId();// 获取锁Boolean success stringRedisTemplate.opsForValue().setIfAbsent(KEY_PREFIX name, threadId , timeoutSec, TimeUnit.SECONDS);return Boolean.TRUE.equals(success);} 在释放锁前先获取锁中线程标识判断与当前线程标识是否一致若一致才执行释放锁操作 Overridepublic void unlock() {// 获取当前线程标识String threadId ID_PREFIX Thread.currentThread().getId();// 获取Redis中记录的锁标识String id stringRedisTemplate.opsForValue().get(KEY_PREFIX name);// 判断线程标识与锁标识是否一致if(threadId.equals(id)){// 一致成功释放锁stringRedisTemplate.delete(KEY_PREFIXname);}} 原子性问题 由于判断锁标识与释放锁并不是原子的可能在判断完锁标识后由于JVM的垃圾回收机制等原因陷入阻塞期间就可能会被其他线程获取锁而后就会导致误删 一看到原子性可能就会想到事务与数据库的事务不同redis的事务可以保证原子性但无法保证数据的一致性。事务中的多个操作其实是在做批处理是在最终一次性去执行的。没有办法先查询然后判断再去释放。因为做查询操作时是拿不到结果的它是最后一次性执行的因此无法将它们放在同一个事务中只能用redis中的一些乐观锁进行一些判断确保在释放时没有人做过修改 我们可以用Lua编写脚本在脚本中编写多条命令确保多条命令执行时的原子性。 -- 获取锁中的线程标识 local id redis.call(get,KEYS[1]) -- 比较线程标识与锁中的标识是否一致 if(idARGV[i]) then-- 释放锁 del keyreturn redis.call(del,KEYS[1]) end return 0 接下来就可以在释放锁的方法中直接调用写好的Lua脚本将原本的多条命令变成只有一条了判断和删除都是在脚本中执行的是能够满足原子性的 private static final DefaultRedisScriptLong UNLOCK_SCRIPT;//初始化脚本static {UNLOCK_SCRIPTnew 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),ID_PREFIXThread.currentThread().getId());} 这种方式就是利用了lua脚本的原子性在里面依次执行多个redis的命令这就能保证原子性 那么本篇文章就到此为止了如果觉得这篇文章对你有帮助的话可以点一下关注和点赞来支持作者哦。如果有什么讲的不对的地方欢迎在评论区指出希望能够和你们一起进步✊
http://www.dnsts.com.cn/news/119698.html

相关文章:

  • 太原网站制作电话电子商务课程视频
  • 汽车行业网站建设方案视频网站怎么赚钱
  • 莱芜网站优化排名公司阳东区建设局网站
  • 网站建设 淘宝运营天津市建设工程协会网站
  • 微信小程序开发网站建设旅游网站推荐
  • 衡水网站建设维护跨境电商东莞网站建设
  • 百度关键字搜索到自己的网站建设网站需要考虑什么
  • 网站网络推广优化厦门关键词seo排名网站
  • 注册公司网站模板下载短视频推广的好处
  • 网站编写语言什么好建设工程规划许可证网站
  • 网站托管服务提供商有网站建wap
  • 网站建设投票系统设计设计公司属于什么企业
  • 网站留言模块app设计理念
  • 凡客衬衫官方网站学服装设计培训机构
  • 合肥行业网站建设洛阳孟津网站建设
  • 有没有免费注册的网站智能网站建设推荐
  • 怎么给网站做缓存河北省建设局材料备案网站
  • 小说网站做公众号好还是网站好软件开发项目管理的核心
  • 久免费域名注册网站水土保持与生态建设网站
  • 为什么进不了中国建设银行网站简单的网站开发
  • 如何建立公司网站建设苏州新区网站制作
  • 网站关停公告怎么做2023年房地产最新消息
  • 武威 网站建设网站投诉平台
  • 电子产品商务网站模板深圳专业专业网站建设
  • 网站建设需要学什么能力做网站项目实例
  • 织梦做的网站怎么加弹窗如何做区块链网站
  • 晋江网站有什么职业做零食网站色调搭配怎么做
  • 淮安企业网站建设中国域名查询
  • 陌上香坊是做盗版的网站吗网站icp备案申请流程
  • 青岛专业餐饮网站制作简述企业网站如何推广