前面兩篇文章說了怎么樣簡單的使用commons-pool庫,這里需要考慮一個問題就是在很多時候我們在池里的對象都是比較重型的並且大多數比較稀缺的 資源,比如說數據庫連接,這樣如果一直把一些連接放在池里不歸還,就會很占資源,並且是這些資源利用率降低,那么怎樣才能更好的管理池子中的資源 呢,commons-pool里提供了一個GenericObjectPool類,它的出現使上面的問題就迎刃而解了。同樣對於 GenericObjectPool類,也就有一個對應的GenericKeyedObjectPool類。
下面還是例子說話
一個Connection類,可以想象成一個遠程連接比如數據庫連接等。其中包括創建連接,關閉連接,和一個print方法。
- package com.googlecode.garbagecan.commons.pool.sample3;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- public class MyConnection {
- private static Logger logger = LoggerFactory.getLogger(MyConnection.class);
- private String name;
- private boolean connected;
- public MyConnection(String name) {
- this.name = name;
- }
- public void connect() {
- this.connected = true;
- logger.info(name + ": " + connected);
- }
- public void close() {
- this.connected = false;
- logger.info(name + ": " + connected);
- }
- public boolean isConnected() {
- return this.connected;
- }
- public String getName() {
- return this.name;
- }
- public void print() {
- logger.info(this.name);
- }
- }
一個PoolableObjectFactory接口的實現類,提供makeObject, activateObject, passivateObject, validateObject, destroyObject方法。
- package com.googlecode.garbagecan.commons.pool.sample3;
- import org.apache.commons.pool.PoolableObjectFactory;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- public class MyConnectionPoolableObjectFactory implements PoolableObjectFactory {
- private static Logger logger = LoggerFactory.getLogger(MyConnectionPoolableObjectFactory.class);
- private static int count = 0;
- public Object makeObject() throws Exception {
- MyConnection myConn = new MyConnection(generateName());
- logger.info(myConn.getName());
- myConn.connect();
- return myConn;
- }
- public void activateObject(Object obj) throws Exception {
- MyConnection myConn = (MyConnection)obj;
- logger.info(myConn.getName());
- }
- public void passivateObject(Object obj) throws Exception {
- MyConnection myConn = (MyConnection)obj;
- logger.info(myConn.getName());
- }
- public boolean validateObject(Object obj) {
- MyConnection myConn = (MyConnection)obj;
- logger.info(myConn.getName());
- return myConn.isConnected();
- }
- public void destroyObject(Object obj) throws Exception {
- MyConnection myConn = (MyConnection)obj;
- logger.info(myConn.getName());
- myConn.close();
- }
- private synchronized String generateName() {
- return "conn_" + (++count);
- }
- }
一個測試類
- package com.googlecode.garbagecan.commons.pool.sample3;
- import org.apache.commons.pool.ObjectPool;
- import org.apache.commons.pool.PoolableObjectFactory;
- import org.apache.commons.pool.impl.GenericObjectPool;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- public class Test {
- private static Logger logger = LoggerFactory.getLogger(Test.class);
- public static void main(String[] args) {
- //test1();
- //test2();
- //test3();
- }
- private static void test1() {
- PoolableObjectFactory factory = new MyConnectionPoolableObjectFactory();
- GenericObjectPool.Config config = new GenericObjectPool.Config();
- config.lifo = false;
- config.maxActive = 5;
- config.maxIdle = 5;
- config.minIdle = 1;
- config.maxWait = 5 * 1000;
- ObjectPool pool = new GenericObjectPool(factory, config);
- for (int i = 0; i < 10; i++) {
- Thread thread = new Thread(new MyTask(pool));
- thread.start();
- }
- //closePool(pool);
- }
- private static void test2() {
- PoolableObjectFactory factory = new MyConnectionPoolableObjectFactory();
- GenericObjectPool.Config config = new GenericObjectPool.Config();
- config.lifo = false;
- config.maxActive = 5;
- config.maxIdle = 5;
- config.minIdle = 1;
- config.maxWait = 20 * 1000;
- ObjectPool pool = new GenericObjectPool(factory, config);
- for (int i = 0; i < 10; i++) {
- Thread thread = new Thread(new MyTask(pool));
- thread.start();
- }
- //closePool(pool);
- }
- private static void test3() {
- PoolableObjectFactory factory = new MyConnectionPoolableObjectFactory();
- GenericObjectPool.Config config = new GenericObjectPool.Config();
- config.lifo = false;
- config.maxActive = 5;
- config.maxIdle = 0;
- config.minIdle = 0;
- config.maxWait = -1;
- ObjectPool pool = new GenericObjectPool(factory, config);
- Thread thread = new Thread(new MyTask(pool));
- thread.start();
- try {
- Thread.sleep(60L * 1000L);
- } catch (Exception e) {
- e.printStackTrace();
- }
- //closePool(pool);
- }
- private static void closePool(ObjectPool pool) {
- try {
- pool.close();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- private static class MyTask implements Runnable {
- private ObjectPool pool;
- public MyTask(ObjectPool pool) {
- this.pool = pool;
- }
- public void run() {
- MyConnection myConn = null;
- try {
- myConn = (MyConnection)pool.borrowObject();
- try {
- myConn.print();
- } catch(Exception ex) {
- pool.invalidateObject(myConn);
- myConn = null;
- }
- Thread.sleep(10L * 1000L);
- } catch(Exception ex) {
- logger.error("Cannot borrow connection from pool.", ex);
- } finally {
- if (myConn != null) {
- try {
- pool.returnObject(myConn);
- } catch (Exception ex) {
- logger.error("Cannot return connection from pool.", ex);
- }
- }
- }
- }
- }
- }
其中包含了三個方法,分別測試了三種情況;
- 類中包含了一個實現了Runnable接口的內部類,目的是為了啟動幾個線程來模擬的對連接類的使用,並且為了盡可能的真實,在run方法里sleep了10秒中;
- 首 先運行測試方法test1()可以看到,在循環10個線程申請Connection類時,前面5個可以很好的獲取,但是后面5個線程就不能獲取連接,並且 拋出了異常,這是由於“config.maxActive = 5;”和“config.maxWait = 5 * 1000;”在起作用,由於配置了最大活動連接是5個,並且后續申請沒有有效連接的等待時間是5秒,所以test1方法中后面五個線程在等了5秒后全部拋 出異常,表明不能申請連接了。
- 下面運行test2()方法,在test2中把“config.maxWait = 20 * 1000;”改成了20秒,而我們程序中每個線程使用連接會用去10秒,所以后面五個線程在等待了10秒后就全部獲取連接了,所以程序最后會運行成功。
- 再 看test3()方法,其中把maxIdle和minIdle都改為0,就是在連接不用時立即真正歸還連接,對於數據庫連接來說就是關閉物理連接,而 maxWait改為-1,就是如果沒有申請到連接就永遠等待,運行test3()方法,觀察日志,可以看出程序在用戶連接對象以后,會調用 MyConnectionPoolableObjectFactory.destroyObject()和MyConnection.close()方法 來銷毀對象。所以如果是使用這樣的配置,就相當於每次都是物理連接,用完后就關閉連接。當然這里是一個極端的例子,真實情況下不會把maxIdle和 minIdle都設為0的。
其實對於GenericObjectPool.Config類和GenericKeyedObjectPool.Config類還是有很多配置參數的,這里只是列出的最簡單的幾個常用的,具體可以參考官方文檔。
來源:http://blog.csdn.net/kongxx/article/details/6612760