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,有可能最終導致負數(其實是與實際活動數不匹配),從而影響到原始設定的最大連接數會不管用。