為什么要用對象池
解決大對象的創(chuàng)建和銷毀時的資源消耗捌锭。所以,常見的對象池有數(shù)據(jù)庫連接池取视、線程池等
Apache Commons-pool2幾個重要對象
- ObjectPool<T>
實現(xiàn)對對象存取和狀態(tài)管理的池實現(xiàn)鬼雀;如:線程池顷窒、數(shù)據(jù)庫連接池
public interface ObjectPool<T> {
//從池子中獲取一個對象
T borrowObject() throws Exception, NoSuchElementException,
IllegalStateException;
//將對象用完后放回到對象池
void returnObject(T obj) throws Exception;
//廢棄對象
void invalidateObject(T obj) throws Exception;
//增加對象
void addObject() throws Exception, IllegalStateException,
UnsupportedOperationException;
//獲取空閑對象個數(shù)
int getNumIdle();
//獲取活躍對象個數(shù)
int getNumActive();
//清除池,池可用
void clear() throws Exception, UnsupportedOperationException;
//關(guān)閉池源哩,池不可用
void close();
}
- PooledObject<T> extends Comparable<PooledObject<T>>
被池化的對象的包裝類鞋吉,在原對象的基礎(chǔ)上添加了一些附加的信息,比如說狀態(tài)信息励烦,創(chuàng)建時間谓着,激活時間,關(guān)閉時間等 - PooledObjectFactory<T>
被池化對象的工廠類坛掠,用于創(chuàng)建對象赊锚、銷毀對象、校驗對象狀態(tài)等
一個示例屉栓,驗證對象的獲取和釋放
- 被池化的對象
/**
* 被池化的對象舷蒲, 此對象將放入對象池中
*
*/
public class BigObject {
private String key;
public BigObject(String key) {
this.key = key;
}
public BigObject() {}
}
- 被池化對象的工廠
/**
* 生產(chǎn)被池化對象的工廠
* @author yaowan
*
*/
public class BigObjectFactory extends BasePooledObjectFactory<BigObject> {
@Override
public BigObject create() throws Exception {
return new BigObject("1");
}
@Override
public PooledObject<BigObject> wrap(BigObject obj) {
return new DefaultPooledObject<BigObject>(obj);
}
/**
* testOnCreate,testOnBorrow之一設(shè)置為true時,
* objectPool.borrowObject()被調(diào)用時友多,會調(diào)用此方法
*
*/
@Override
public boolean validateObject(PooledObject<BigObject> p) {
//用一個隨機(jī)數(shù)據(jù)來模擬對象是否失效
if (new Random().nextInt(10) < 6) {
System.out.println(Thread.currentThread().getName()+" 對象失效牲平。。域滥。纵柿。。骗绕。藐窄。");
return false;
}
System.out.println(Thread.currentThread().getName()+" 對象有效。酬土。荆忍。。。刹枉。叽唱。");
return true;
}
}
- 使用對象池中的對象
public class BigObjectProvider {
private ObjectPool<BigObject> objectPool;
public BigObjectProvider(ObjectPool<BigObject> objectPool) {
this.objectPool = objectPool;
}
public void use() {
System.out.println(Thread.currentThread().getName() + " 準(zhǔn)備取對象。微宝。棺亭。。蟋软。镶摘。");
System.out.println(objectPool.getNumActive() + "," + objectPool.getNumIdle());
// 獲得對應(yīng)key的對象
BigObject connectionTest1 = null;
try {
connectionTest1 = objectPool.borrowObject();
System.out.println(Thread.currentThread().getName() + " borrowObject = {" + connectionTest1 + "}");
System.out.println(Thread.currentThread().getName() + " 已取得對象,正在使用中岳守。凄敢。。湿痢。涝缝。。譬重。");
Thread.sleep(2000);
} catch (NoSuchElementException e) {
System.out.println(convert2String(org.apache.commons.lang3.exception.ExceptionUtils.getStackFrames(e)));
//再次請求使用
use();
} catch (IllegalStateException e) {
//對象放回對象池出錯拒逮,拋出來的異常
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (connectionTest1 != null) {
// 釋放對象
try {
objectPool.returnObject(connectionTest1);
System.out.println(
Thread.currentThread().getName() + objectPool.getNumActive() + "," + objectPool.getNumIdle());
System.out.println(Thread.currentThread().getName() + " 歸還對象。臀规。滩援。。塔嬉。狠怨。。");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
public static String convert2String(String[] strings) {
StringBuilder builder = new StringBuilder();
for (String string : strings) {
builder.append(string).append("\n");
}
return builder.toString();
}
}
/**
* 模擬使用過程
* 啟動兩個線程來競爭使用邑遏,通過打印的信息來熟知整個過程
*
*/
public class UseCase {
public static void main(String[] args) {
GenericObjectPoolConfig config = new GenericObjectPoolConfig();
//當(dāng)“連接池”中active數(shù)量達(dá)到閥值時佣赖,即“鏈接”資源耗盡時,連接池需要采取的手段
config.setBlockWhenExhausted(true);
config.setMaxTotal(1);
//設(shè)置為true時记盒,在GenericObjectPool<T>.borrowObject(long)方法調(diào)用獲取不到對象時憎蛤,會調(diào)用
//PooledObjectFactory<T>.validateObject(PooledObject<T>)驗證是否要釋放對象
//此時對象池中沒有對象時,會拋出NoSuchElementException異常
config.setTestOnBorrow(true);
config.setTestOnCreate(true);
BigObjectFactory factory = new BigObjectFactory();
final ObjectPool<BigObject> objectPool = new GenericObjectPool<>(PoolUtils.synchronizedPooledFactory(factory),config);
final BigObjectProvider provider = new BigObjectProvider(objectPool);
final int execNum = 3;
new Thread(new Runnable() {
@Override
public void run() {
for(int i=0;i< execNum;i++) {
System.out.println(Thread.currentThread().getName()+" 第"+i+"次使用前");
provider.use();
System.out.println(Thread.currentThread().getName()+" 第"+i+"次使用后");
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
for(int i=0;i< execNum;i++) {
System.out.println(Thread.currentThread().getName()+" 第"+i+"次使用前");
provider.use();
System.out.println(Thread.currentThread().getName()+" 第"+i+"次使用后");
}
}
}).start();
}
}
- 運行結(jié)果
Thread-1 第0次使用前
Thread-1 準(zhǔn)備取對象纪吮。俩檬。。碾盟。棚辽。。
0,0
Thread-2 第0次使用前
Thread-2 準(zhǔn)備取對象冰肴。屈藐。榔组。。联逻。搓扯。
0,0
Thread-1 對象失效。包归。锨推。。公壤。换可。。
java.util.NoSuchElementException: Unable to validate object
at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:506)
at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:363)
at org.poker.common.objectpool.BigObjectProvider.use(BigObjectProvider.java:23)
at org.poker.common.objectpool.UseCase$1.run(UseCase.java:41)
at java.lang.Thread.run(Thread.java:745)
Thread-1 準(zhǔn)備取對象厦幅。锦担。。慨削。。套媚。
0,0
Thread-1 對象有效缚态。。堤瘤。玫芦。。本辐。桥帆。
Thread-1 borrowObject = {org.poker.common.objectpool.BigObject@6f8225a}
Thread-1 已取得對象,正在使用中慎皱。老虫。。茫多。祈匙。。天揖。
Thread-10,1
Thread-1 歸還對象夺欲。。今膊。些阅。。斑唬。市埋。
Thread-1 第0次使用后
Thread-1 第1次使用前
Thread-1 準(zhǔn)備取對象黎泣。。腰素。聘裁。。弓千。
Thread-2 對象失效衡便。。洋访。镣陕。。姻政。呆抑。
1,0
Thread-2 對象有效。汁展。鹊碍。。食绿。侈咕。。
Thread-2 borrowObject = {org.poker.common.objectpool.BigObject@19ebee92}
Thread-2 已取得對象器紧,正在使用中耀销。。铲汪。熊尉。。掌腰。狰住。
Thread-20,1
Thread-2 歸還對象。齿梁。转晰。。士飒。查邢。。
Thread-2 第0次使用后
Thread-2 第1次使用前
Thread-2 準(zhǔn)備取對象酵幕。扰藕。。芳撒。邓深。未桥。
Thread-1 對象失效。芥备。冬耿。。萌壳。亦镶。。
1,0
Thread-1 對象有效袱瓮。缤骨。。尺借。绊起。。。
Thread-1 borrowObject = {org.poker.common.objectpool.BigObject@39c46fff}
Thread-1 已取得對象,正在使用中谴咸。。笋鄙。。谨读。。坛吁。
Thread-10,1
Thread-1 歸還對象劳殖。。拨脉。哆姻。。玫膀。矛缨。
Thread-1 第1次使用后
Thread-1 第2次使用前
Thread-1 準(zhǔn)備取對象。帖旨。箕昭。。解阅。落竹。
Thread-2 對象失效。货抄。朱转。藤为。。。。
1,0
Thread-2 對象有效。忌愚。硕糊。撬腾。。。碟刺。
Thread-2 borrowObject = {org.poker.common.objectpool.BigObject@1dd47977}
Thread-2 已取得對象者填,正在使用中蜜暑。铐姚。。肛捍。隐绵。。拙毫。
Thread-20,1
Thread-2 歸還對象依许。。缀蹄。峭跳。。缺前。蛀醉。
Thread-2 第1次使用后
Thread-2 第2次使用前
Thread-2 準(zhǔn)備取對象。诡延。滞欠。古胆。肆良。。
Thread-1 對象失效逸绎。惹恃。。棺牧。巫糙。。颊乘。
1,0
Thread-1 對象失效参淹。醉锄。。浙值。恳不。。开呐。
java.util.NoSuchElementException: Unable to validate object
at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:506)
at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:363)
at org.poker.common.objectpool.BigObjectProvider.use(BigObjectProvider.java:23)
at org.poker.common.objectpool.UseCase$1.run(UseCase.java:41)
at java.lang.Thread.run(Thread.java:745)
Thread-1 準(zhǔn)備取對象烟勋。。筐付。卵惦。。瓦戚。
0,0
Thread-1 對象有效沮尿。。伤极。蛹找。。哨坪。庸疾。
Thread-1 borrowObject = {org.poker.common.objectpool.BigObject@507e8ea4}
Thread-1 已取得對象,正在使用中当编。届慈。。忿偷。金顿。。鲤桥。
Thread-10,1
Thread-2 對象有效揍拆。。茶凳。嫂拴。。贮喧。筒狠。
Thread-1 歸還對象。箱沦。辩恼。。。灶伊。疆前。
Thread-1 第2次使用后
Thread-2 borrowObject = {org.poker.common.objectpool.BigObject@507e8ea4}
Thread-2 已取得對象,正在使用中聘萨。峡继。。匈挖。碾牌。。儡循。
Thread-20,1
Thread-2 歸還對象舶吗。。择膝。誓琼。。肴捉。腹侣。
Thread-2 第2次使用后
通過在對象池中放入1個對象,來觀察對象的獲取和釋放過程齿穗,以及在并發(fā)環(huán)境下對象安全問題