中斷了一段時間,再次開始技術之旅;心里有個小目標,先把對象池技術梳理清楚。
![]()
1、為什么用對象池
在 java 中,對象的生命周期包括對象創建、對象使用,對象消失三個時間段,其中對象的使用是對象真正需要存活的時間,不好修改,該用的時候還得使用啊。對象的創建和消失就得好好控制下了。對象的創建是比較費時間的,也許感覺不到,好比一個賦值操作int i=1
,也是需要耗時的,在比如構造一個對象,一個數組就更加消耗時間。再說對象的消除,在 java 里面使用 GC 來進行對象回收,其實也是需要對對象監控每一個運行狀態,包括引用,賦值等。在 Full GC 的時候,會暫停其他操作,獨占 CPU。所以,我們需要控制對象的創建數量,也不要輕易的讓對象消失,讓他的復用更加充分。
2、對象池
對象池其實就是一個集合,里面包含了我們需要的對象集合,當然這些對象都被池化了,也就是被對象池所管理,想要這樣的對象,從池子里取個就行,但是用完得歸還。對象池的對象最好是創建比較費時的大對象,如果是太簡單的對象,再進入池化的時間比自己構建還多,就不劃算了。可以理解對象池為單例模式的延展,多例模式,就那么幾個對象實例,再多沒有了。
3、自定義一個低質量的對象池
首先構造一個池化對象,也就是對實際對象封裝下,為什么呢?當然是為了讓對象池更好的管理
public class PooledObject<T> {
private T objection = null;// 外界使用的對象
private boolean busy = false; // 此對象是否正在使用的標志,默認沒有正在使用
// 構造函數,池化對象
public PooledObject(T objection) {
this.objection = objection;
}
// 返回此對象中的對象
public T getObject() {
return objection;
}
// 設置此對象的,對象
public void setObject(T objection) {
this.objection = objection;
}
// 獲得對象對象是否忙
public boolean isBusy() {
return busy;
}
// 設置對象的對象正在忙
public void setBusy(boolean busy) {
this.busy = busy;
}
}
池化對象現在包括兩個屬性,一個是原始對象的引用,另外一個表示當前對象是否在使用
接下來把對象池寫出來
import java.util.Enumeration;
import java.util.Vector;
public abstract class ObjectPool<T> {
public static int numObjects = 10; // 對象池的大小
public static int maxObjects = 50; // 對象池最大的大小
protected Vector<PooledObject<T>> objects = null; // 存放對象池中對象的向量(PooledObject類型)
public ObjectPool() {
}
/*** 創建一個對象池 ***/
public synchronized void createPool() {
// 確保對象池沒有創建。如果創建了,保存對象的向量 objects 不會為空
if (objects != null) {
return; // 如果己經創建,則返回
}
// 創建保存對象的向量 , 初始時有 0 個元素
objects = new Vector<PooledObject<T>>();
for (int i = 0; i < numObjects; i++) {
objects.addElement(create());
}
}
public abstract PooledObject<T> create();
public synchronized T getObject() {
// 確保對象池己被創建
if (objects == null) {
return null; // 對象池還沒創建,則返回 null
}
T t = getFreeObject(); // 獲得一個可用的對象
// 如果目前沒有可以使用的對象,即所有的對象都在使用中
while (t == null) {
wait(250);
t = getFreeObject(); // 重新再試,直到獲得可用的對象,如果
// getFreeObject() 返回的為 null,則表明創建一批對象后也不可獲得可用對象
}
return t;// 返回獲得的可用的對象
}
/**
* 本函數從對象池對象 objects 中返回一個可用的的對象,如果 當前沒有可用的對象,則創建幾個對象,并放入對象池中。
* 如果創建后,所有的對象都在使用中,則返回 null
*/
private T getFreeObject() {
// 從對象池中獲得一個可用的對象
T obj = findFreeObject();
if (obj == null) {
createObjects(10); // 如果目前對象池中沒有可用的對象,創建一些對象
// 重新從池中查找是否有可用對象
obj = findFreeObject();
// 如果創建對象后仍獲得不到可用的對象,則返回 null
if (obj == null) {
return null;
}
}
return obj;
}
public void createObjects(int increment){
for (int i = 0; i < increment; i++) {
if (objects.size() > maxObjects) {
return;
}
objects.addElement(create());
}
}
/**
* 查找對象池中所有的對象,查找一個可用的對象, 如果沒有可用的對象,返回 null
*/
private T findFreeObject() {
T obj = null;
PooledObject<T> pObj = null;
// 獲得對象池向量中所有的對象
Enumeration<PooledObject<T>> enumerate = objects.elements();
// 遍歷所有的對象,看是否有可用的對象
while (enumerate.hasMoreElements()) {
pObj = (PooledObject<T>) enumerate.nextElement();
// 如果此對象不忙,則獲得它的對象并把它設為忙
if (!pObj.isBusy()) {
obj = pObj.getObject();
pObj.setBusy(true);
}
}
return obj;// 返回找到到的可用對象
}
/**
* 此函數返回一個對象到對象池中,并把此對象置為空閑。 所有使用對象池獲得的對象均應在不使用此對象時返回它。
*/
public void returnObject(T obj) {
// 確保對象池存在,如果對象沒有創建(不存在),直接返回
if (objects == null) {
return;
}
PooledObject<T> pObj = null;
Enumeration<PooledObject<T>> enumerate = objects.elements();
// 遍歷對象池中的所有對象,找到這個要返回的對象對象
while (enumerate.hasMoreElements()) {
pObj = (PooledObject<T>) enumerate.nextElement();
// 先找到對象池中的要返回的對象對象
if (obj == pObj.getObject()) {
// 找到了 , 設置此對象為空閑狀態
pObj.setBusy(false);
break;
}
}
}
/**
* 關閉對象池中所有的對象,并清空對象池。
*/
public synchronized void closeObjectPool() {
// 確保對象池存在,如果不存在,返回
if (objects == null) {
return;
}
PooledObject<T> pObj = null;
Enumeration<PooledObject<T>> enumerate = objects.elements();
while (enumerate.hasMoreElements()) {
pObj = (PooledObject<T>) enumerate.nextElement();
// 如果忙,等 0.5 秒
if (pObj.isBusy()) {
wait(500); // 等
}
// 從對象池向量中刪除它
objects.removeElement(pObj);
}
// 置對象池為空
objects = null;
}
/**
* 使程序等待給定的毫秒數
*/
private void wait(int mSeconds) {
try {
Thread.sleep(mSeconds);
} catch (InterruptedException e) {
}
}
}
為了泛化處理,這個對象池是個抽象類,接下來具體實現一個
public class DefaultObjectPool extends ObjectPool<String> {
@Override
public PooledObject<String> create(){
return new PooledObject<String>(new String(""+1));
}
}
最后測試下:
public static void main(String[] args) {
ObjectPool<String> objPool = new DefaultObjectPool();
objPool.createPool();
String obj = objPool.getObject();
objPool.returnObject(obj);
objPool.closeObjectPool();
}
4、開源的對象池
上面的例子基本夠用,但是commons-pool提供了一套很好用的對象池組件,使用也很簡單。
org.apache.commons.pool.ObjectPool定義了一個簡單的池化接口,有三個對應實現,與我們的 Vector 這個集合不同的是,commons-pool提供了多樣的集合,包括先進先出(FIFO),后進先出(LIFO)
StackObjectPool
:實現了后進先出(LIFO)行為。
SoftReferenceObjectPool
: 實現了后進先出(LIFO)行為。另外,對象池還在SoftReference 中保存了每個對象引用,允許垃圾收集器針對內存需要回收對象。
KeyedObjectPool定義了一個以任意的key訪問對象的接口(可以池化對種對象),有兩種對應實現。
GenericKeyedObjectPool
:實現了先進先出(FIFO)行為。
StackKeyedObjectPool
: 實現了后進先出(LIFO)行為。
PoolableObjectFactory 定義了池化對象的生命周期方法,我們可以使用它分離被池化的不同對象和管理對象的創建,持久,銷毀。
BasePoolableObjectFactory
這個實現PoolableObjectFactory接口的一個抽象類,我們可用擴展它實現自己的池化工廠。