• ShardedJedisPool 中可用连接数的小bug


    ShardedJedisPool中,returnBrokenResource() 及 returnResource() ,为施放资源、关闭连接的方法,若重复调用,导致 _numActive 当前活动数一直递减,会出现负数的情况。

    假如在一个方法中设置了三个jedis连接,在获取第一或第二个连接时出现异常,在抛出异常或者finally中总是施放这三个资源,会导致池中的连接连续施放三次,从而变成负数。

    这样会出现连接池最大连接数配置无效的情况。

    以下片段代码:

    public class RedisUtil {
        public static ShardedJedisPool pool;
        static {
            JedisPoolConfig config = new JedisPoolConfig();// Jedis池配置
            config.setMaxActive(2);// 最大活动的对象个数
            config.setMaxIdle(1000 * 60);// 对象最大空闲时间
            config.setMaxWait(1000 * 3);// 获取对象时最大等待时间
            config.setTestOnBorrow(true);
            String hostA = "192.168.0.99";
            int portA = 6380;
            List<JedisShardInfo> jdsInfoList =new ArrayList<JedisShardInfo>(1);
            JedisShardInfo infoA = new JedisShardInfo(hostA, portA);
            jdsInfoList.add(infoA);
            pool = new ShardedJedisPool(config, jdsInfoList);
        }
        
        public static void testRedis() {
            
            ShardedJedis jedis = null;
            ShardedJedis jedis1 = null;
            ShardedJedis jedis2 = null;
            try {
                // 从池中获取三次连接
                jedis = pool.getResource();
                jedis1 = pool.getResource();
                jedis2 = pool.getResource();
                
                String value = jedis.get("wuse");
                String value1 = jedis1.get("wuse");
                if (null == value || "".equals(value)) {
                    jedis.set("wuse", "testWuse");
                    jedis.expire("wuse", 20);
                }else {
                    System.out.println(value);
                }
            } catch (Exception e) {
                e.printStackTrace();
                
                // 异常时关闭连接,此处可以注释
            } finally {
                pool.returnBrokenResource(jedis);
                pool.returnBrokenResource(jedis1);
                pool.returnBrokenResource(jedis2);
            }
        }
    }

    比如,设置的最大连接数为3,当第一次获取连接1和连接2的时候,没有问题,获取第三个连接的时候,由于最大连接数为2,所以抛异常

    走finally之后,释放掉三个连接资源,这时候,pool连接池的当前活动数竟然为-1

    所以,第二次再调用testRedis()方法时,由于之前pool的活动数为-1,这次三个连接都能获取成功,不抛异常。

    -------------------------------------------------------------------------------

    ShardedJedisPool类本身继承Pool类,Pool类中用了org.apache.commons.pool.impl.GenericObjectPool类来当做连接池,而Pool类初始化时,需要传入PoolableObjectFactory工厂类,在ShardedJedisPool类中自定义了一个继承BasePoolableObjectFactory类的工厂类ShardedJedisFactory,而ShardedJedisFactory类中的销毁方法destroyObject()方法中,从传进来的ShardedJedis对象里获取了镜像连接,继承的最顶层Sharded类中的getAllShards()方法,实际上只是通过Collections工具类获取了resources的value集合的镜像,所以实际上也就是说只是意义上释放了连接。 

    而ShardedJedisPool类中的returnBrokenResource()方法,实际上调用的是GenericObjectPool类的invalidateObject()方法,而每次调用后,总会再去做 _numActive --,也就是说,每次调用,当前活动数都会减1,有可能最终导致负数(其实是与实际活动数不匹配),从而影响到原始设定的最大连接数会不管用。

  • 相关阅读:
    通过调用C语言的库函数与在C代码中使用内联汇编两种方式来使用同一个系统调用来分析系统调用的工作机制
    解密腾讯课堂视频缓存文件
    Pycharm启动后加载anaconda一直updating indices造成Pycharm闪退甚至电脑崩溃
    Pycharm基本设置和插件安装
    Pycharm配置anaconda环境
    Anaconda管理Python环境
    Markdown介绍及工具推荐
    Android应用性能测试
    常用的adb命令
    QTP入门——玩玩小飞机
  • 原文地址:https://www.cnblogs.com/anranwuse/p/3698052.html
Copyright © 2020-2023  润新知