Java通用对象池GenericObjectPool原理总结和自定义的Jedis管理池例子

在java中,有很多池管理的概念,典型的如线程池数据库连接池,查看源码会发现这些池管理类都是继承于GenericObjectPool<T>,所以了解GenericObjectPool的工作机制,对进一步理解java中常用的池很有帮助,这样当我们使用这些池管理类时能做到心中有数,另外当我们需要用自定义的池管理类管理我们一些特殊的对象时,也能实现。

了解GenericObjectPool<T>,应该从其构造方法入手

GenericObjectPool<T>(PooledObjectFactory<T>factory, GenericObjectPoolConfig config)

创建一个对象池,需要传入两个参数PooledObjectFactory<T> factory和GenericObjectPoolConfigconfig,其中config是池管理类的一些参数配置,比如最小对象数量最大对象数量超时时间等,由于它有默认值,所以只需对关键的参数进行设置即可,比如最大对象管理数量。

下面以自创建的Jedis管理池为例:

JedisFactory.java

public class JedisFactory extendsBasePooledObjectFactory<Jedis>{

         publicPooledObject<Jedis> makeObject(){

                   Jedisjedis = new Jedis("127.0.0.1",6379);

                   jedis.connect();

                   System.out.println(jedis.isConnected());

                   return  new DefaultPooledObject<Jedis>(jedis);

         }

         publicvoid destroyObject(Jedis jedis){

                   jedis.close();

         }

         publicboolean validateObject(Jedis jedis) {

                   if(jedis.isConnected()){

                            returntrue;

                   }else{

                            returnfalse;

                   }

         }

 

         @Override

         publicPooledObject<Jedis> wrap(Jedis arg0) {

                   //TODO Auto-generated method stub

                   returnnull;

         }

         @Override

         publicJedis create() throws Exception {

                   //TODO Auto-generated method stub

                   returnnull;

         }

 

}

 

GenericObjectPoolTest.java

public class GenericObjectPoolTest extendsGenericObjectPool<Jedis>{

         publicGenericObjectPoolTest(JedisFactory factory,GenericObjectPoolConfig config){

                   super(factory,config);

         }

        

         publicstatic void main(String[] args){

                   GenericObjectPoolConfigconfig=new GenericObjectPoolConfig();

                   config.setMinIdle(10);

                   config.setMaxTotal(10);

                   config.setMaxWaitMillis(30000);

                   JedisFactoryjedisFactory=new JedisFactory();

                   GenericObjectPoolTestredisPool=new GenericObjectPoolTest(jedisFactory,config);

                   Jedisjedis=null;

                   try{

                            jedis=redisPool.borrowObject();//获取池中对象

                            jedis.select(0);

                            jedis.set("test","pooltest");

                            System.out.println(redisPool.getNumActive());

                   }catch (Exception e) {

                            //TODO Auto-generated catch block

                            e.printStackTrace();

                   }finally{

                            redisPool.returnObject(jedis);//归还池中对象

                            System.out.println(redisPool.getNumActive());

                   }

         }

}

不需要redis自带的JedisPool池管理类,上面两个文件就实现了简单的Jedis池管理类

-- GenericObjectPool的工作原理后续补充

GenericObjectPool的工作原理流程:

1.构造方法

当我们执行构造方法时,主要工作就是创建了一个存储对象的LinkedList类型容器,也就是概念意义上的“池”。

2.从对象池中获取对象

从上面的例子可以看出,获取池中的对象是通过borrowObject()命令,源码比较复杂,简单而言就是去LinkedList中获取一个对象,如果不存在的话,要调用构造方法中第一个参数Factory工厂类的makeObject()方法去创建一个对象再获取,获取到对象后要调用validateObject方法判断该对象是否是可用的,如果是可用的才拿去使用。LinkedList容器减一。

--这就是为什么我们必须要继承并重写Factory工厂类的makeObject()和validateObject方法

3.归还对象到线程池

从上面的例子可以看出,归还对象到线程池是通过returnObject方法实现,简单而言就是先调用validateObject方法判断该对象是否是可用的,如果可用则归还到池中,LinkedList容器加一,如果是不可以的则则调用destroyObject方法进行销毁。

--这就是为什么我们必须要继承并重写Factory工厂类的destroyObject方法。

 

最简单的流程就是这样了,由于取和还的流程步骤都在borrowObject和returnObject方法中固定的,所以我们只要重写Factory工厂类的makeObject()和validateObject以及destroyObject方法即可实现最简单的池的管理控制,通过构造方法传入该Factory工厂类对象则可以创建最简单的对象池管理类。这算是比较好的解耦设计模式。

补充:

borrowObject中还要一重要步骤,就是activateObject(Objectobj)**对象,只要成功**可用的对象才会被使用,否则就直接destroyObject,所谓的**就是对特定对象分配它需要的资源,并非所有类型对象都需要,所以对于不需要的类型而言不重写也可以。另外还有一步,当池中的对象已经被取光,但是创建的活跃对象数量已经超过config设置的最大值MaxAtive时,就不能再创建对象,只能阻塞等待其他使用者归还对象。阻塞用wait()实现。

returnObject中也还有一重要步骤,就是passivateObject(Objectobj)钝化对象,所谓钝化就是对特定对象释放它占用的资源,并非所有类型对象都需要,所以对于不需要的类型而言不重写也可以。归还时判断在池中可以对象数量是否超过config设置的最大值MaxIdle,超过则认为池中对象足够,不需要归还,直接销毁。另外还有一步,就是归还对象后调用notify方法唤醒等待对象的线程。

--所以要是实现更完善的池管理类还需要重写activateObject和passivateObject方法

下面流程图说明:

Java通用对象池GenericObjectPool<T>原理总结和自定义的Jedis管理池例子