zoukankan      html  css  js  c++  java
  • 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,有可能最终导致负数(其实是与实际活动数不匹配),从而影响到原始设定的最大连接数会不管用。

  • 相关阅读:
    如何编写一个简单的依赖注入容器
    网站框架的动态编译的实现原理
    Python实现语音识别和语音合成
    OpenCV图像处理以及人脸识别
    Shell教程快速入门
    TensorFlow入门教程
    如何免费使用Google的GPU跑深度学习代码
    高等数学系列文章
    Git系列教程
    一键构造你的博客园目录
  • 原文地址:https://www.cnblogs.com/anranwuse/p/3698052.html
Copyright © 2011-2022 走看看