https://blog.csdn.net/tiane5hao/article/details/85957840
對於共享資源,有一個很著名的設計模式:資源池。該模式正是為了解決資源頻繁分配、釋放所造成的問題的。把該模式應用到數據庫連接管理領域,就是建立一個數據庫連接池,提供一套高效的連接分配、使用策略,最終目標是實現連接的高效、安全的復用。還有一類對象池大家可能不太了解,對於nio中有個堆外內存,netty的ByteBuf對象的實現就是一個可復用的對象池來提高性能。連接池大家平時聽的多,使用也多,但是自己實現應該比較少。
先寫一個簡單通用的對象池
總共包含幾個類,代碼如下:
ICommonPool : 定義通用池,借出對象和歸還對象
PoolFactory :對象工廠,負責創建和銷毀對象
PoolConfig : 對象池的配置(最大連接數和最小連接數)
BaseCommonPool :對象池的主要基礎實現
// An highlighted block package test.pool; /** * 通用池接口定義 * @param <T> */ public interface ICommonPool<T> { /** * 租借對象 */ T borrowObject() throws Exception; /** * 返回對象池 */ void returnObject(T object) throws Exception; }
package test.pool;
/** * 負責創建、銷毀對象 * @param <T> */ public interface PoolFactory<T> { /** * 創建對象 * @return */ T makeObject(); /** * 銷毀對象 */ void destroyObject(); }
package test.pool; /** * 對象池配置 */ public class PoolConfig { // 池中最大對象 private int maxTotal = 8; //初始化對象數 private int minTotal = 0; public int getMaxTotal() { return maxTotal; } public void setMaxTotal(int maxTotal) { this.maxTotal = maxTotal; } public int getMinTotal() { return minTotal; } public void setMinTotal(int minTotal) { this.minTotal = minTotal; } }
package test.pool; import java.util.concurrent.LinkedBlockingQueue; /** * 對象池的基礎實現 * 這里用阻塞隊列來實現 * @param <T> */ public class BaseCommonPool<T> implements ICommonPool<T> { private LinkedBlockingQueue<T> pool; private PoolConfig poolConfig; private PoolFactory<T> poolFactory; public BaseCommonPool(PoolConfig poolConfig, PoolFactory<T> poolFactory){ this.poolConfig = poolConfig; this.poolFactory = poolFactory; initCommonPool(); } private void initCommonPool() { //代表池的大小 pool = new LinkedBlockingQueue<T>(poolConfig.getMaxTotal()); while (poolConfig.getMinTotal() > pool.size()){ T obj = poolFactory.makeObject(); pool.offer(obj); } } /** * 租借對象 */ public T borrowObject() throws Exception{ //如果隊列中對象為空,poll方法返回null,非阻塞(take方法阻塞) T obj = pool.poll(); if(obj != null){ return obj; } return poolFactory.makeObject(); } /** * 返回對象池 */ public void returnObject(T object) throws Exception{ //offer方法非阻塞,如果隊列滿了,直接拋棄,返回false,與put方法的區別自行百度 if(!pool.offer(object)){ poolFactory.destroyObject(); } } }
通過上面的通用池實現jedis連接池
實現類如下:
MyRedisFactory : jedis的對象工廠
MyRedisPool : jedis連接池
jedis pom依賴
<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency>
package test.objectpool; import redis.clients.jedis.Jedis; import test.pool.PoolFactory; public class MyRedisFactory implements PoolFactory<Jedis> { public MyRedisFactory() { } public Jedis makeObject() { Jedis jedis = new Jedis("127.0.0.1",6379); jedis.connect(); return jedis; } public void destroyObject(Jedis jedis) { if (jedis.isConnected()) { try { try { jedis.quit(); } catch (Exception var4) { ; } jedis.disconnect(); } catch (Exception var5) { ; } } } }
package test.objectpool; import redis.clients.jedis.Jedis; import test.pool.BaseCommonPool; import test.pool.PoolConfig; public class MyRedisPool extends BaseCommonPool<Jedis> { public MyRedisPool(PoolConfig config) { super( config, new MyRedisFactory()); } }
連接池測試
下面是jedis連接池和非連接池的測試(單線程),對於多線程后續測試了再補上,測試執行1萬次本地redis方法get耗時比對結果如下:
線程池執行耗時1153 ms
創建redis執行耗時5437 ms
性能有着明顯的提升
package test.objectpool; import redis.clients.jedis.Jedis; import test.pool.PoolConfig; public class PoolTest { public static void main(String[] args) { PoolConfig poolConfig = new PoolConfig(); poolConfig.setMaxTotal(8); poolConfig.setMinTotal(4); MyRedisPool myRedisPool = new MyRedisPool(poolConfig); //線程池執行 long start = System.currentTimeMillis(); for(int i = 0; i < 10000; i++){ Jedis jedis = null; try { jedis = myRedisPool.borrowObject(); String result = jedis.get("aaa"); // System.out.println(result); }catch (Exception e){ e.printStackTrace(); }finally { myRedisPool.returnObject(jedis); } } System.out.println("線程池執行耗時" + (System.currentTimeMillis() - start)); //創建redis執行 start = System.currentTimeMillis(); for(int i = 0; i < 10000; i++){ Jedis jedis = null; try { jedis = new Jedis("127.0.0.1", 6379); String result = jedis.get("aaa"); // System.out.println(result); }catch (Exception e){ e.printStackTrace(); }finally { jedis.close(); } } System.out.println("創建redis執行耗時" + (System.currentTimeMillis() - start)); } }