zoukankan      html  css  js  c++  java
  • 多线程测试redisson实现分布式锁出现org.redisson.RedissonShutdownException: Redisson is shutdown

    多线程测试redisson实现分布式锁出现org.redisson.RedissonShutdownException: Redisson is shutdown。

    原因:多线程还没跑完,主线程就跑完了。主线程走完,关闭了资源。redisson关闭,多线程操作redisson报错:Redisson is shutdown。

    解决办法:主线程等待多线程跑完。Thread.sleep(30000);。

    1.Junit测试类:RedisDistributedLockTest

    package com.user.test.spring_redis;
    
    import java.util.HashSet;
    import java.util.Iterator;
    import java.util.Set;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    import com.user.service.redis.SecondKillService;
    import com.user.service.redis.SecondKillServiceImp;
    import com.user.service.redis.SecondKillThread;
    
    @RunWith(SpringJUnit4ClassRunner.class) 
    @ContextConfiguration({"classpath:applicationContext.xml"})
    public class RedisDistributedLockTest extends AbstractJUnit4SpringContextTests{
        @Autowired
        private SecondKillService secondKillService;
        @Autowired
        private SecondKillThread secondKillThread;
        
        /**
         * 模拟秒杀
         */
        @Test
        public void secKill(){
            System.out.println("秒杀活动开始---");
            try {
                for(int i=0;i<2000;i++){
                    new Thread(secondKillThread,"Thread" + i).start();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            try {
                // 主线程需要等待线程执行完,否则,其他线程还没执行完,主线程就走完了,redisson会报错:Redisson is shutdown
                Thread.sleep(30000);
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
            System.out.println(SecondKillServiceImp.list);
            Set set = new HashSet();
            for(int i : SecondKillServiceImp.list){
                int count = 0;
                for(int j : SecondKillServiceImp.list){
                    if(i == j){
                        count = count + 1;
                    }
                }
                if(count > 1){
                    set.add(i);
                }
            }
            if(set != null && set.size() > 0){
    //            Iterator it = set.iterator();
    //            while(it.hasNext()){
    //                System.out.println(it.next());
    //            }
                System.out.println(set);
            }else{
                System.out.println("没有重复的记录!");
            }
        }
    }

    2.线程类:SecondKillThread

    package com.user.service.redis;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    @Component
    public class SecondKillThread implements Runnable{
        @Autowired
        private SecondKillService secondKillService;
        
        @Override
        public void run() {
            secondKillService.seckill();
        }
    }

    3.秒杀业务接口:SecondKillService

    package com.user.service.redis;
    
    public interface SecondKillService {
        public void seckill();
    }

    4.秒杀业务实现类:SecondKillServiceImp

    package com.user.service.redis;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.TimeUnit;
    
    import org.apache.commons.lang3.StringUtils;
    import org.redisson.api.RLock;
    import org.redisson.api.RedissonClient;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    import com.user.base.utils.redis.DistributedLockUtils;
    import com.user.base.utils.redis.DistributedLockUtils2;
    import com.user.base.utils.redis.redisson.RedissonConfig;
    
    @Service
    public class SecondKillServiceImp implements SecondKillService{
        @Autowired
        private RedissonClient redissonClient;
        private static int count = 2000;
        public static List<Integer> list = new ArrayList<>();
        
        @Override
        public void seckill() {
    //        count = count - 1;
    //        list.add(count);
    //        System.out.println(Thread.currentThread().getName() + "秒杀操作,singleRedis," + "剩余数量:" + count);
            // 可以防止重复提交的数据。
            String uuid = DistributedLockUtils2.lockWithTimeout("test", 10);
            // 上锁,如果锁一直保持,其他线程无法操作,只有过期或者主动释放锁。
            if(StringUtils.isNotEmpty(uuid)){
                try {
                    count = count - 1;
                    list.add(count);
                    System.out.println(Thread.currentThread().getName() + "秒杀操作,singleRedis," + "剩余数量:" + count);
                } catch (Exception e) {
                    //e.printStackTrace();
                } finally {
                    // 如果业务代码出现异常了,不在finally中执行释放锁的操作,也会导致锁无法释放。
                    DistributedLockUtils2.releaseLock("test",uuid);
                }
            }else{
                System.out.println("获取锁超时!");
            }
        }
        
    //    @Override
    //    public void seckill() {
    //        RLock redissonLock = redissonClient.getLock("test");
    //        // 相当于distributedLockUtil.stringRedisTemplate.opsForValue().setIfAbsent(lockKey, identifier, timeout, TimeUnit.SECONDS)
    //        redissonLock.lock();
    //        try {
    //            count = count - 1;
    //            list.add(count);
    //            System.out.println(Thread.currentThread().getName() + "秒杀操作,clusterRedis," + "剩余数量:" + count);
    //        } catch (Exception e) {
    //            e.printStackTrace();
    //        } finally {
    //            // 相当于distributedLockUtil.stringRedisTemplate.delete(lockKey);
    //            /*
    //             * 由于开启了watchdog看门狗线程监听,所以线程执行完之前不会出现:A线程锁过期时间过期,此时B线程设置锁,然后又切换到A线程删锁,误删B线程的锁。
    //             * 因为A线程执行完之前,A线程的锁会一直续命,不会过期。所以A线程在delete锁之前,会一直持有锁。
    //             * 如果服务器非宕机情况,那么锁会一直续命,A线程一直持有锁。最终都会执行到finally释放锁。
    //             * 如果中间出现宕机,那么锁不会续命,到了过期时间就会过期。锁自动释放。
    //             * 因此不会出现锁无法释放,死锁的情况。
    //             * 
    //             * 自己写续命比较麻烦,而且容易出错。redisson是个很好的框架和解决方案。
    //             */
    //            redissonLock.unlock();
    //        }
    //    }
    }
  • 相关阅读:
    Web.xml配置详解
    JAVA的StringBuffer类
    工作空间造成的javaweb项目无法新建
    典型程序实现代码汇总(1)
    TCP/UDP常见端口参考
    HTTP状态码详解
    struts2的java.lang.NoSuchMethodException异常处理
    python学习之路-6 冒泡算法、递归、反射、os/sys模块详解
    python学习之路-5 基础进阶篇
    python学习之路-4 内置函数和装饰器
  • 原文地址:https://www.cnblogs.com/super-chao/p/15229895.html
Copyright © 2011-2022 走看看