博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Apache commons-pool对象池妙用
阅读量:6306 次
发布时间:2019-06-22

本文共 9900 字,大约阅读时间需要 33 分钟。

hot3.png

前言

大多时候,我们获取对象的方法都是直接new一个。但是,对于大对象的构造,或者构造耗时比较久的对象,我们每次要使用都去new一个是很不科学的。比如数据库的连接对象、redis的连接对象、Http连接请求对象等等。

针对这种场景我们可以创建对象池,这个对象池中维护一定数量的对象,需要的时候就从这个对象池中获取对象,使用完后返还给对象池。这样就避免构造对象所带来的耗时,提升了系统的性能。

为了避免造轮子,我们采用Apache commons-pool对象实现:

org.apache.commons
commons-pool2
2.4.2

实现对象池

ObjectPool的主要方法:

//从对象池中获取对象的方法    T borrowObject() throws Exception, NoSuchElementException,            IllegalStateException;    //将对象返还给对象池    void returnObject(T obj) throws Exception;    //让对象失效    void invalidateObject(T obj) throws Exception;    //往对象池中新增一个对象    void addObject() throws Exception, IllegalStateException,            UnsupportedOperationException;    //获取当前闲置在对象池中的对象数量,即没有被拿走使用的对象数量    int getNumIdle();    //获取已经在使用中的对象数量,即被使用者从对象池中拿走使用的数量    int getNumActive();    //清空对象池中闲置的所有对象    void clear() throws Exception, UnsupportedOperationException;    //关闭对象池    void close();

PooledObject,抽象了对象池中对象应该具备的一些属性。注意,这个对象并不是我们真正要存的对象,而是经过一层封装的对象,那么真正存放在对象池的其实都是经过封装过的对象,即PooledObject对象。

PooledObjectFactory抽象工厂模型:

public interface PooledObjectFactory
{ //构造一个封装对象 PooledObject
makeObject() throws Exception; //销毁对象 void destroyObject(PooledObject
p) throws Exception; //验证对象是否可用 boolean validateObject(PooledObject
p); //激活一个对象,使其可用用 void activateObject(PooledObject
p) throws Exception; //钝化一个对象,也可以理解为反初始化 void passivateObject(PooledObject
p) throws Exception;}

以连接池为例

DbConnection对象:

public class DbConnection {    private Boolean isActive;    public Boolean getActive() {        return isActive;    }    public void setActive(Boolean active) {        isActive = active;    }}

创建对象工厂DbConnectionFactory:

public class DbConnectionFactory implements PooledObjectFactory
{ @Override public PooledObject
makeObject() throws Exception { DbConnection dbConnection = new DbConnection(); //构造一个新的连接对象 return new DefaultPooledObject<>(dbConnection); } @Override public void destroyObject(PooledObject
p) throws Exception { //断开连接 p.getObject().setActive(false); } @Override public boolean validateObject(PooledObject
p) { //判断这个对象是否是保持连接状态 return p.getObject().getActive(); } @Override public void activateObject(PooledObject
p) throws Exception { //激活这个对象,让它连接上数据库 p.getObject().setActive(true); } @Override public void passivateObject(PooledObject
p) throws Exception { //不处理 }}

测试例子:

public static void main(String[] args) {        DbConnectionFactory factory = new DbConnectionFactory();        //设置对象池的相关参数        GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();        poolConfig.setMaxIdle(20);        poolConfig.setMaxTotal(100);        poolConfig.setMinIdle(5);        //新建一个对象池,传入对象工厂和配置        GenericObjectPool
objectPool = new GenericObjectPool<>(factory, poolConfig); DbConnection dbConnection = null; try { //从对象池获取对象,如果 dbConnection = objectPool.borrowObject(); System.out.println(dbConnection.getActive()); //使用改对象 } catch (Exception e) { e.printStackTrace(); } finally { if (dbConnection != null) { //返还对象 objectPool.returnObject(dbConnection); } } }

上面的例子中,池化的对象是一样的,如果想池化不一样的对象,可以采用键值对的对象GenericKeyedObjectPool 。

比如新的DbConnection包含多个字段:

public class DbConnection2 {    private Boolean isActive;    private String url;    public String getUrl() {        return url;    }    public void setUrl(String url) {        this.url = url;    }    public Boolean getActive() {        return isActive;    }    public void setActive(Boolean active) {        isActive = active;    }}

实现KeyedPooledObjectFactory 类:

public class DbConnectionKeyFactory implements KeyedPooledObjectFactory
{ @Override public PooledObject
makeObject(String key) throws Exception { DbConnection2 dbConnection2 = new DbConnection2(); dbConnection2.setUrl(key); dbConnection2.setActive(true); return new DefaultPooledObject<>(dbConnection2); } @Override public void destroyObject(String key, PooledObject
p) throws Exception { p.getObject().setActive(false); } @Override public boolean validateObject(String key, PooledObject
p) { return p.getObject().getActive(); } @Override public void activateObject(String key, PooledObject
p) throws Exception { p.getObject().setActive(true); } @Override public void passivateObject(String key, PooledObject
p) throws Exception { }}

换一个多线程测试:

public static void run() {        GenericObjectPoolConfig conf = new GenericObjectPoolConfig();        conf.setMaxTotal(18);        conf.setMaxIdle(10);        StringPoolFactory factory = new StringPoolFactory();        final GenericObjectPool
objectPool = new GenericObjectPool<>(factory, conf); for (int i = 0; i < 10; i++) { new Thread(new Runnable() { @Override public void run() { while (true) { try { String result = objectPool.borrowObject(); System.out.println("result :" + result); Thread.sleep(100); objectPool.returnObject(result); } catch (InterruptedException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } } }).start(); } }

创建的对象一直被复用:

StringPoolFactory对象:

public class StringPoolFactory implements PooledObjectFactory
{ public StringPoolFactory() { System.out.println("init string factory.."); } @Override public void activateObject(PooledObject
pool) throws Exception { // TODO Auto-generated method stub } @Override public void destroyObject(PooledObject
pool) throws Exception { String str = pool.getObject(); if (str != null) { str = null; System.out.println(str + " destroy..."); } } @Override public PooledObject
makeObject() throws Exception { String i = UUID.randomUUID().toString(); System.out.println("make " + i + " success..."); return new DefaultPooledObject
(i); } @Override public void passivateObject(PooledObject
pool) throws Exception { // TODO Auto-generated method stub } @Override public boolean validateObject(PooledObject
pool) { // TODO Auto-generated method stub return false; }}

使用GenericKeyedObjectPool 对象:

public static void main(String[] args) {        GenericKeyedObjectPoolConfig genericKeyedObjectPoolConfig = new GenericKeyedObjectPoolConfig();        genericKeyedObjectPoolConfig.setMaxIdlePerKey(10);        genericKeyedObjectPoolConfig.setMaxTotalPerKey(100);        genericKeyedObjectPoolConfig.setMaxTotal(500);        genericKeyedObjectPoolConfig.setMinIdlePerKey(10);        DbConnectionKeyFactory dbConnectionKeyFactory = new DbConnectionKeyFactory();        GenericKeyedObjectPool
genericKeyedObjectPool = new GenericKeyedObjectPool<> (dbConnectionKeyFactory, genericKeyedObjectPoolConfig); DbConnection2 dbConnection1 = null; DbConnection2 dbConnection2 = null; try { dbConnection1 = genericKeyedObjectPool.borrowObject("192.168.0.1"); dbConnection2 = genericKeyedObjectPool.borrowObject("192.168.0.2"); System.out.println(dbConnection1.getUrl()); System.out.println(dbConnection2.getUrl()); } catch (Exception e) { e.printStackTrace(); } finally { if (dbConnection1 != null) { genericKeyedObjectPool.returnObject(dbConnection1.getUrl(), dbConnection1); } if (dbConnection2 != null) { genericKeyedObjectPool.returnObject(dbConnection2.getUrl(), dbConnection2); } } }

Config包含的参数:

public static void initConfig(GenericObjectPoolConfig cfg){				  	cfg.setLifo( Boolean.valueOf(SysParamsToolkit.getProperty("lifo", "true"))); 	        cfg.setMaxTotal( Integer.valueOf(SysParamsToolkit.getProperty("maxActive", "18"))); 	        cfg.setMaxIdle( Integer.valueOf(SysParamsToolkit.getProperty("maxIdle", "10"))); 	        cfg.setMaxWaitMillis( Integer.valueOf(SysParamsToolkit.getProperty("maxWait", "150000"))); 	        cfg.setMinEvictableIdleTimeMillis(Integer.valueOf(SysParamsToolkit.getProperty("minEvictableIdleTimeMillis", "100000"))); 	        cfg.setMinIdle(Integer.valueOf(SysParamsToolkit.getProperty("minIdle", "0"))); 	        cfg.setNumTestsPerEvictionRun(Integer.valueOf(SysParamsToolkit.getProperty("numTestsPerEvictionRun", "1"))); 	        cfg.setTestOnBorrow(Boolean.valueOf(SysParamsToolkit.getProperty("testOnBorrow", "false"))); 	        cfg.setTestOnReturn(Boolean.valueOf(SysParamsToolkit.getProperty("testOnReturn", "false"))); 	        cfg.setTestWhileIdle(Boolean.valueOf(SysParamsToolkit.getProperty("testWhileIdle", "false"))); 	        cfg.setTimeBetweenEvictionRunsMillis(Integer.valueOf(SysParamsToolkit.getProperty("timeBetweenEvictionRunsMillis", "120000"))); //	        cfg.whenExhaustedAction = Byte.valueOf("whenExhaustedAction", 1); 	        cfg.setBlockWhenExhausted(false);	}

转载于:https://my.oschina.net/u/1000241/blog/3028076

你可能感兴趣的文章
[USB-Blaster] Error (209040): Can't access JTAG chain
查看>>
TreeSet的用法
查看>>
防HTTP慢速攻击的nginx安全配置
查看>>
深入理解PHP内核(十四)类的成员变量及方法
查看>>
Spring Boot2.0+中,自定义配置类扩展springMVC的功能
查看>>
参与博客编辑器改版,我的礼物 感谢51cto
查看>>
JavaWeb笔记——JSTL标签
查看>>
Eclipse插件大全 挑选最牛的TOP30
查看>>
一些实用性的总结与纠正
查看>>
Kubernetes概念
查看>>
逻辑卷管理器(LVM)
查看>>
一个小代码,欢迎大佬的意见,求指正
查看>>
搭建LAMP架构
查看>>
神经网络注意力机制--Attention in Neural Networks
查看>>
Spring.Net+WCF实现分布式事务
查看>>
在Linux上高效开发的7个建议
查看>>
java数据结构 - 数组使用的代码
查看>>
个人简历-项目经验
查看>>
swoole异步任务task处理慢请求简单实例
查看>>
oracle数据泵导入分区表统计信息报错(四)
查看>>