zoukankan      html  css  js  c++  java
  • 使用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;
        }
  • 相关阅读:
    什么是CDN?哪些是流行的jQuery CDN?使用CDN有什么好处?
    jQuery 中$.get()和$.post()提交有区别吗?
    window.onload()函数和jQuery中的document.ready()区别
    js相等(==)与全等(===)的区别
    用javascript改变onclick调用的函数
    null,undefined,undeclared的区别
    JavaScript重定向到其他网页
    C Programing Environment
    转:JMir——Java版热血传奇2之资源文件与地图
    PHP内容管理项目函数列表
  • 原文地址:https://www.cnblogs.com/thinkingandworkinghard/p/10627994.html
Copyright © 2011-2022 走看看