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

德商网站建设优化关键词规则

德商网站建设,优化关键词规则,网站空间一般多大,河南建设工程信息网 高级职称 赵静飞 证书文章目录 分布式锁Redis setnxredis锁误删Lua脚本 分布式锁 当我们的项目服务器不只是一台(单体),而是部署在多态服务器上(集群/分布式),同样会出现线程安全问题。不同服务器内部有不同的JVM,每…

文章目录

        • 分布式锁
            • Redis setnx
            • redis锁误删
            • Lua脚本

分布式锁

当我们的项目服务器不只是一台(单体),而是部署在多态服务器上(集群/分布式),同样会出现线程安全问题。不同服务器内部有不同的JVM,每个JVM里面有不同的锁监视器,每一个锁都可以有一个线程获取。

在这里插入图片描述

所以我们要想办法让多个JVM共享同一个锁监视器。

在这里插入图片描述

分布式锁:

满足分布式系统或集群模式下多进程可见并且互斥的锁,主要有3种方式:

在这里插入图片描述

  • MySQL:

    利用数据库的 唯一索引约束行锁 特性,确保同一时刻只有一个进程能获取锁。

    //创建锁
    CREATE TABLE distributed_lock (id INT PRIMARY KEY AUTO_INCREMENT,lock_key VARCHAR(64) UNIQUE, -- 唯一约束owner VARCHAR(64),          -- 锁持有者标识expire_time DATETIME        -- 锁过期时间
    );//获取锁
    -- 尝试插入锁记录(唯一键冲突则失败)
    INSERT INTO distributed_lock (lock_key, owner, expire_time) 
    VALUES ('resource_lock', 'client_123', NOW() + INTERVAL 30 SECOND);
    //若插入成功,表示获取锁;若失败(唯一键冲突),则锁被其他进程占用。//释放锁
    DELETE FROM distributed_lock 
    WHERE lock_key = 'resource_lock' AND owner = 'client_123';//锁超时处理:
    DELETE FROM distributed_lock WHERE expire_time < NOW();
    
  • Redis

    利用 Redis 的setnx实现锁的互斥性和自动过期。

    SETNX key value

    指定的key不存在时,将key的值设为value,如果设置成功返回1,如果key已经存在,就不做任何操作,返回0。

    多个客户端同时尝试设置同一个key,只有一个能成功获取锁(非阻塞:没获取到就放弃而不是等待),从而获得锁。

    也给锁设置过期时间,到时间自动释放,避免死锁发生

  • Zookeeper:

    利用 ZooKeeper 的 临时顺序节点 实现锁的互斥和自动释放。

    有序性:线程来,每次创建一个临时节点,节点IP递增,约定id最小的哪个算他获取锁成功。

    唯一性:所有线程都创建相同名称的节点,同样也只有一个能获取成功。

    这个知识点就不在这里展开讲述。

我们采用redis:

Redis setnx

在这里插入图片描述

public SimpleRedisLock(String name, StringRedisTemplate stringRedisTemplate) {this.name = name;this.stringRedisTemplate = stringRedisTemplate;}private boolean tryLock(long timeoutSec) {// 获取线程标示String threadId = Thread.currentThread().getId();// 获取锁Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(KEY_PREFIX + name, threadId, timeoutSec, TimeUnit.SECONDS);return BooleanUtil.isTrue(flag);}private void unlock(String key) {stringRedisTemplate.delete(key);}
  • 这里为什么返回的是BooleanUtil.isTrue(flag)而不直接是flag?

    Boolean是一个包装类,它可以是true、false或者null。

    setIfAbsent操作在成功设置键时返回true,如果键已经存在则返回false,redis连接异常时,可能会返回null。

    当flag为null时,自动拆箱(Boolean->boolean)会抛出NullPointerException

    BooleanUtil.isTrue:用于安全地将Boolean对象转换为boolean值,处理null的情况,例如,当flag为null时,该方法会返回false。

代码:

 // 5.一人一单Long userId = UserHolder.getUser().getId();// 创建锁对象SimpleRedisLock redisLock = new SimpleRedisLock("order:" + userId, stringRedisTemplate);// 尝试获取锁boolean isLock = redisLock.tryLock(1200);// 判断if(!isLock){// 获取锁失败,直接返回失败或者重试return Result.fail("不允许重复下单!");}try {//略} finally {// 释放锁redisLock.unlock();}
redis锁误删

在某些情况下,上面也会出现问题:

当线程1获取到redis锁后由于某种原因阻塞时间过长,时间超过了redis设置的过期时间,那么redis锁自动释放。这个时候线程2来获取这个锁成功了,这个时候线程1的业务完成了,线程1就直接把这个redis锁给释放了,而线程2还在执行自己的业务,这是线程3也来获取锁成功,也执行业务,可能再次发生线程安全问题。

在这里插入图片描述

所以我们的解决方案就是:在释放锁之前通过线程标识查看是否是自己的锁

在这里插入图片描述

代码:

//使用UUID(不同JVM,UUID不同)
private static final String ID_PREFIX = UUID.randomUUID().toString(true) + "-";public SimpleRedisLock(String name, StringRedisTemplate stringRedisTemplate) {this.name = name;this.stringRedisTemplate = stringRedisTemplate;}@Overridepublic boolean tryLock(long timeoutSec) {// 获取线程标示String threadId = ID_PREFIX + Thread.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();// 获取锁中的标示String id = stringRedisTemplate.opsForValue().get(KEY_PREFIX + name);// 判断标示是否一致if(threadId.equals(id)) {// 释放锁stringRedisTemplate.delete(KEY_PREFIX + name);}}
Lua脚本

但是,同样也存在问题:当线程1判断了锁是自己的后,要准备释放这个锁的时候发生了阻塞(JVM内部垃圾回收),锁过期,线程2来获得,线程1恢复正常后直接就释放锁。

所以,我们要确保判断+释放锁是一个原子性操作

Redis提供Lua脚本功能,在一个脚本中编写多条redis命令,确保多条命令执行时的原子性。

Lua 教程 | 菜鸟教程

静态脚本:
在这里插入图片描述

不写死的话,用参数:

在这里插入图片描述

Lua如何结合到java里:

  • 创建脚本

    在这里插入图片描述

    -- 比较线程标示与锁中的标示是否一致
    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);}
    
  • execute()调用脚本

    @Overridepublic void unlock() {// 调用lua脚本stringRedisTemplate.execute(UNLOCK_SCRIPT,Collections.singletonList(KEY_PREFIX + name),ID_PREFIX + Thread.currentThread().getId());}
    

在这里插入图片描述
不断学习中,感谢大家的观看>W<


文章转载自:

http://F1pRkpDF.mjpgL.cn
http://LX9SDILB.mjpgL.cn
http://ImPLAPyw.mjpgL.cn
http://4iQy84l6.mjpgL.cn
http://Ez17Ek55.mjpgL.cn
http://IHNQQEWN.mjpgL.cn
http://Vq4bRs5U.mjpgL.cn
http://1emar8uA.mjpgL.cn
http://8BHvRUCa.mjpgL.cn
http://yAe6ay8W.mjpgL.cn
http://1uwLAtNh.mjpgL.cn
http://nD6EEgFK.mjpgL.cn
http://niDCxy2E.mjpgL.cn
http://rG9tNLAU.mjpgL.cn
http://iMKwuKEz.mjpgL.cn
http://tspPZ4yb.mjpgL.cn
http://wboW9PWh.mjpgL.cn
http://BQgML5mo.mjpgL.cn
http://sUUkMO2e.mjpgL.cn
http://biJZF7v0.mjpgL.cn
http://99njismx.mjpgL.cn
http://MikOtudu.mjpgL.cn
http://XDQX07Gs.mjpgL.cn
http://tDEdufaO.mjpgL.cn
http://kypoG4EO.mjpgL.cn
http://VScLi8R2.mjpgL.cn
http://yQdTCdVy.mjpgL.cn
http://QIso8VMl.mjpgL.cn
http://Fwic6Tz1.mjpgL.cn
http://gtqyTHhc.mjpgL.cn
http://www.dtcms.com/wzjs/611149.html

相关文章:

  • 购物网站开发的背景与意义好的网站开发公司
  • 上海网站建设q.479185700強郴州网站建设哪家好
  • 手机网站维护费怎么创造自己的网站
  • 安徽网站备案网站后台备份丢失
  • 互联网做网站属于什么行业我想建网站
  • 石家庄网站建设哪家便宜oppo手机商城
  • 海南网站设计wordpress主题购买
  • 佛山做网站公司深圳向失业人员发放补贴
  • 微商的自己做网站叫什么名字温州网页设计招聘信息网
  • 淘宝客做网站链接做网站工作室找客户难
  • 备案 网站名称 重复个人备案做门户网站
  • 网站建设公司一年赚多少私密浏览器怎么看片
  • 网站建设售后服务方案机关门户网站 建设 方案
  • 深圳市网站建设做网站济南建网站
  • 网站建设优化服务如何福州网站制
  • 大兴模版网站开发公司哪家好建设个网站多少钱
  • 网站页面关键词优化个人网页框架模板
  • 苍溪县城乡建设投资有限公司网站细谈电商网站外链建设的策略
  • 个人网站制作工具箱安卓版国内几个做外贸的网站
  • 学校网站建设报价表找客网怎么样
  • 网站开发接单长沙注册公司流程与费用
  • 大连建设学院网站企业网站建设策划书
  • 网站开发时间网站设计怎么设计学生作业
  • 新东方研学网站那家公司做的湛江网站建站建设
  • 网站开发培训怎么样互联网是指哪些工作
  • 怎样免费做自己的网站合肥网站建设工作室
  • 电商网站建设策划书模板管理咨询顾问
  • 淄博网站建设设计专业h5网站制作
  • app网站开发长沙游戏推广话术
  • 网站域名空间怎么提交搬家公司电话号码