commons-pool2中GenericKeyedObjectPool应用demo
2016-05-27
用commons-pool可以管理一些数据库连接池等东西,也可以结合动态代理实现自己的一些共有业务。
maven依赖:
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> <version>2.4.1</version> </dependency>
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.10</version> </dependency>
MyBean测试对象,对象池存管理该对象:
package littlehow.commons.demo.pool; import java.sql.Timestamp; /** * MyBean * * @author littlehow * @time 2016-05-27 11:11 */ public class MyBean { public static final String[] names = {"Littlehow", "Jim Green", "Black Tom", "White Cat", "Yellow Dog", "Color Wolf"}; /** * bean被初始化的时间 */ private long instanceTime = System.currentTimeMillis(); /** * 名称 */ private String name; /** * 对象是否存活 */ private boolean live = true; /** * 实例化对象 */ public MyBean () { this.name = names[(int)(this.instanceTime % names.length)]; } /** * name由调用方指定 * @param name */ public MyBean (String name) { this.name = name; } /** * 销毁方法 */ public void beKilled () { System.out.print("我[" + this.name + "]居然被销毁了,我不甘心啊,"); System.out.println("就活了[" + (System.currentTimeMillis() - this.instanceTime) +"]毫秒!"); } public String toString () { return "我[" + this.name + "]出生在:" + new Timestamp(this.instanceTime); } /** * 获取实例化时间 * @return */ public long getInstanceTime () { return this.instanceTime; } /** * 获取对象标志 * @return */ public String getName () { return this.name; } /** * 死亡掉 */ public void deadBean () { this.live = false; } /** * 人不是还活着 * @return */ public boolean isLive () { return this.live; } /** * 相当于打开一个链接对象,如果是管理数据库连接的话 */ public void start () { System.out.println(this.name + "的生命开始了"); } }
KeyPoolFactory对象池工厂
package littlehow.commons.demo.pool; import org.apache.commons.pool2.BaseKeyedPooledObjectFactory; import org.apache.commons.pool2.PooledObject; import org.apache.commons.pool2.impl.DefaultPooledObject; import org.apache.commons.pool2.impl.GenericKeyedObjectPool; import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig; /** * KeyPoolFactory 带key的对象工厂 * * @author littlehow * @time 2016-05-27 11:28 */ public class KeyPoolFactory { /** * 对象池 */ private static GenericKeyedObjectPool<String, MyBean> pool; /** * 对象池的参数设置 */ private static final GenericKeyedObjectPoolConfig config; /** * 对象池每个key最大实例化对象数 */ private final static int TOTAL_PERKEY = 10; /** * 对象池每个key最大的闲置对象数 */ private final static int IDLE_PERKEY = 3; static { config = new GenericKeyedObjectPoolConfig (); config.setMaxTotalPerKey(TOTAL_PERKEY); config.setMaxIdlePerKey(IDLE_PERKEY); /** 支持jmx管理扩展 */ config.setJmxEnabled(true); config.setJmxNamePrefix("myPoolProtocol"); /** 保证获取有效的池对象 */ config.setTestOnBorrow(true); config.setTestOnReturn(true); } /** * 从对象池中获取对象 * @param key * @return * @throws Exception */ public static MyBean getBean (String key) throws Exception { if (pool == null) { init(); } return pool.borrowObject(key); } /** * 归还对象 * @param key * @param bean */ public static void returnBean (String key, MyBean bean) { if (pool == null) { init(); } pool.returnObject(key , bean); } /** * 关闭对象池 */ public synchronized static void close () { if (pool !=null && !pool.isClosed()) { pool.close(); pool = null; } } /** * 初始化对象池 */ private synchronized static void init () { if (pool != null) return; pool = new GenericKeyedObjectPool<String, MyBean>(new MyBeanPooledFactory(), config); } /** * 对象工厂 */ static class MyBeanPooledFactory extends BaseKeyedPooledObjectFactory<String, MyBean> { /** * 创建对象 * @param key * @return * @throws Exception */ public MyBean create(String key) throws Exception { MyBean myBean = new MyBean(); myBean.start(); System.out.println(myBean); return myBean; } public PooledObject<MyBean> wrap(MyBean value) { return new DefaultPooledObject<MyBean>(value); } /** * 验证对象是否有效 * @param key * @param p * @return */ public boolean validateObject(String key, PooledObject<MyBean> p) { MyBean bean = p.getObject(); if(!bean.isLive()){ System.out.println(bean.getName() + "已经死了,无法唤醒他了!"); return false; } return true; } /** * 销毁 * @param key * @param p * @throws Exception */ public void destroyObject(String key, PooledObject<MyBean> p) throws Exception { /** 杀死他 */ p.getObject().beKilled(); } public void activateObject(String key, PooledObject<MyBean> p) throws Exception { super.activateObject(key, p); } public void passivateObject(String key, PooledObject<MyBean> p) throws Exception { super.passivateObject(key, p); } } }
GetBean测试类
package littlehow.commons.demo.pool; import org.junit.Test; import java.util.Random; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.TimeUnit; import static org.junit.Assert.*; /** * GetBean 测试从对象池中获取对象 * * @author littlehow * @time 2016-05-27 14:03 */ public class GetBean { static String[] keys = {"2016052700", "2016052800", "2016052900"}; /** 随机key */ Random r = new Random(); /** * 获取key值 * @return */ String getKey () { return keys[r.nextInt(keys.length)]; } /** * 获取对象 */ @Test public void getBean () { String key = getKey(); /** 保证key值长度为10 */ assertTrue( "key的长度必须为10", key != null && key.length() == 10 ); try { /** * 同一个key最多可以获取10个对象 * 可以看出,当获取10个对象时,对象池就再也不能给出对象了 */ for (int i = 0; i < 20; i ++) { TimeUnit.SECONDS.sleep(1);//睡一秒 KeyPoolFactory.getBean(key); } /** 可以看出拿对象时阻塞的 */ System.out.println("前方是否阻塞到我了..."); } catch (Exception e) { e.printStackTrace(); } } /** * 获取对象再还回去 */ @Test public void getAndReturnBean () { String key = getKey(); /** 保证key值长度为10 */ assertTrue( "key的长度必须为10", key != null && key.length() == 10 ); try { /** * 同一个key最多可以获取10个对象 * 可以看出,当获取10个对象时,对象池就再也不能给出对象了 */ for (int i = 0; i < 20; i ++) { TimeUnit.SECONDS.sleep(1);//睡一秒 MyBean my = KeyPoolFactory.getBean(key); /** 让对象死掉 */ my.deadBean(); /** 归还对象 * 因为执行了my.deadBean(),这时候在归还对象时,他发现对象已经 * 不合法了,这时候工厂就会重新拿对象 * 如果屏蔽掉my.deadBean()这样的方法,那么获取到的对象将是第一次获取到的对象 */ KeyPoolFactory.returnBean(key, my); } } catch (Exception e) { e.printStackTrace(); } } /** * 多个key同时去获取bean */ @Test public void getBeans () { String key1 = getKey(); String key2 = key1; while (key1.equals(key2)) { key2 = getKey(); } assertTrue( "key的长度必须为10,而获取到的key1="+key1, key1 != null && key1.length() == 10 ); assertTrue( "key的长度必须为10,而获取到的key2="+key2, key2 != null && key2.length() == 10 ); try { /** * 同一个key最多可以获取10个对象 * 20个对象用2个key就可以全部输出 * 这些都是不归还的 */ for (int i = 0; i < 20; i ++) { TimeUnit.SECONDS.sleep(1);//睡一秒 if (i % 2 == 0){ KeyPoolFactory.getBean(key1); } else { KeyPoolFactory.getBean(key2); } } /** * 可以看出这句输出了 */ System.out.println("前方是否阻塞到我了..."); } catch (Exception e) { e.printStackTrace(); } } /** * 一个线程借对象,一个线程还对象 * 如果获取和归还的时间差特别大,会导致某些时候线程阻塞,因为对象已经拿完了 * 就好像借书一样,如果书被借完了,那么再想借就得需要等借书人还书了。 */ volatile boolean dead = false;//死亡对象标志 @Test public void getAndReturnByThread () { /** 对象缓存 */ final ConcurrentHashMap<String, LinkedBlockingDeque<MyBean>> beans = new ConcurrentHashMap<String, LinkedBlockingDeque<MyBean>>(); /** * 借对象,每秒借一个 */ new Thread("borrow") { public void run(){ while (true) { String key = getKey(); LinkedBlockingDeque<MyBean> link = beans.get(key); if (link == null) { /** 最多存放10个对象 */ link = new LinkedBlockingDeque<MyBean>(10); beans.put(key, link); } try { MyBean bean = KeyPoolFactory.getBean(key); link.push(bean); System.out.println(Thread.currentThread().getName() + "操作:key=" + key + ",bean=" + bean); TimeUnit.SECONDS.sleep(1); } catch (Exception e) { e.printStackTrace(); } } } }.start(); /** * 还对象,每3秒还一个 */ new Thread("return") { public void run () { while (true) { String key = getKey(); LinkedBlockingDeque<MyBean> link = beans.get(key); if (link == null || link.size() == 0) continue; /** 弹出元素 */ MyBean bean = link.pop(); if (dead) { bean.deadBean(); dead = false; } System.out.println(Thread.currentThread().getName() + "操作:key="+key + ",bean="+bean); KeyPoolFactory.returnBean(key, bean); try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } } } }.start(); /** * 每5秒死亡一对象 */ new Thread("dead") { public void run () { while (true) { try { TimeUnit.SECONDS.sleep(5); dead = true; } catch (InterruptedException e) { e.printStackTrace(); } } } }.start(); try { TimeUnit.MINUTES.sleep(5);//5分钟后结束程序 Runtime.getRuntime().exit(0); } catch (Exception e) { } } }