• 使用redis 处理高并发场景


    1.原理: 当同一个用户获取锁之后,会让该用户一直持有锁。同样 的用户再次获取,会根据原子性 ,lock返回true。

     /**
         * 获取锁(非公平锁), 默认获取超时为2分钟
         */
        public boolean lock(){
            return lock(GETLOCK_TIMEOUT/1000);
        }
        /**
         * 获取锁(非公平锁), 获取超时为timeoutSeconds秒
         */
        public boolean lock(int timeoutSeconds){
            int timeout = timeoutSeconds*1000;
            while (timeout >= 0) {
                //在同一个JVM内,防止出现以下情况:当已经获取此锁的线程实际业务运行时间超过LOCK_EXPIRE_TIMEOUT时,此锁会再被其它线程获取
                if(LOCKED_NAMES.contains(lockname)){
                    int sleeptime = random.nextInt(100)+100;
                    try{Thread.sleep(sleeptime);} catch (InterruptedException e) {}
                    timeout -= sleeptime;
                    continue;
                }
                //当分布式程序获取同一个锁时,防止出现以下情况:当已经获取此锁的进程(物理机器)实际业务运行时间超过LOCK_EXPIRE_TIMEOUT时,此锁会再被其它进程(物理机器)获取
                String hearbeatFlag = RedisCacheUtil.get(lockname + HEARTBEAT_SUFFIX , String.class );
                if(hearbeatFlag!=null){
                    int sleeptime = random.nextInt(100)+100;
                    try{Thread.sleep(sleeptime);} catch (InterruptedException e) {}
                    timeout -= sleeptime;
                    continue;
                }
                
                //锁到期时间
                long expires = System.currentTimeMillis() + LOCK_EXPIRE_TIMEOUT + 1;
                boolean ok = setNX(expires);
                if (ok) {
                    //System.out.println(Thread.currentThread().getName()+":获得锁成功,通过setNX");
                    LOCKED_NAMES.add(lockname);
                    locked = true;
                    return locked;
                }
                //获取当前锁信息
                RedisLockValue redisLockValue = get();
                if (redisLockValue != null && redisLockValue.getExpireTime() < System.currentTimeMillis()) {
                    //利用getSet的原子性操作来设置并获取到旧值
                    RedisLockValue oldRedisLockValue = getSet(expires);
                    //最先设置的获取锁
                    if (oldRedisLockValue != null && oldRedisLockValue.getToken().equals(redisLockValue.getToken())) {
                        //System.out.println(Thread.currentThread().getName()+":获得锁成功,通过getSet");
                        LOCKED_NAMES.add(lockname);
                        locked = true;
                        return locked;
                    }
                }
                //防止饥饿线程出现 采用随机休眠时间
                int sleeptime = random.nextInt(100)+100;
                try{Thread.sleep(sleeptime);} catch (InterruptedException e) {}
                timeout -= sleeptime;
            }
            
            //如果已经超时,但只是因为此时缓存还有值,因为反序列化异常导致GET取不到时,解决死锁问题
            try{Thread.sleep(300);} catch (InterruptedException e) {}
            RedisLockValue redisLockValue = get();
            if(redisLockValue==null){
                //强制删掉即可
                LOCKED_NAMES.remove(lockname);
                RedisCacheUtil.delete(lockname);
                RedisCacheUtil.delete( lockname + HEARTBEAT_SUFFIX );
            }
            return locked;
        }
  • 相关阅读:
    conda 激活环境失败解决办法
    openSmile-2.3.0在Linux下安装
    Ubuntu16.04下安装多版本cuda和cudnn
    几个最新免费开源的中文语音数据集
    train loss与test loss结果分析
    文件路径
    Properties类与配置文件
    内省
    Junit单元测试
    Hdfs常用命令
  • 原文地址:https://www.cnblogs.com/thinkingandworkinghard/p/10627994.html
Copyright © 2020-2023  润新知