一個Connection類,能夠想象成一個遠程鏈接好比數據庫鏈接等。其中包括建立鏈接,關閉鏈接,和一個print方法。
java
[java] view plaincopyprint?數據庫
package com.googlecode.garbagecan.commons.pool.sample3; apache
import org.slf4j.Logger; 測試
import org.slf4j.LoggerFactory; this
public class MyConnection { google
private static Logger logger = LoggerFactory.getLogger(MyConnection.class); spa
private String name; .net
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方法。
[java] view plaincopyprint?
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);
}
}
一個測試類
[java] view plaincopyprint?
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類仍是有不少配置參數的,這裏只是列出的最簡單的幾個經常使用的,具體能夠參考官方文檔。