Java對象池pool2使用


對象池的定義:
對象的實例化是最耗費性能的操作之一,這在過去是個大問題,現在不用再過分關注它。但當我們處理封裝外部資源的對象(如數據庫連接)時,對象的創建操作則會耗費很多資源。
解決方案是 重用共享這些創建成本高昂的對象,這稱為 對象池模式(創建型模式)
 
直接上代碼:
1、對象工廠類
package com.zc.demo;

import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.PooledObjectFactory;
import org.apache.commons.pool2.impl.DefaultPooledObject;

public class SeatNumFactory implements PooledObjectFactory<SeatNum> {

    // 創建對象 或 引用現有對象
    @Override
    public PooledObject<SeatNum> makeObject() throws Exception {
        System.out.println("【創建對象】");
        return new DefaultPooledObject<SeatNum>(new SeatNum());
    }
    // 銷毀對象
    @Override
    public void destroyObject(PooledObject<SeatNum> pooledObject) throws Exception {
        System.out.println("【銷毀對象】,剩余數量="+pooledObject.getObject().num);
        pooledObject.deallocate();// 銷毀
    }
    // 驗證對象
    @Override
    public boolean validateObject(PooledObject<SeatNum> pooledObject) {
        System.out.println("【驗證對象】數量="+pooledObject.getObject().num);
        return pooledObject.getObject().num > 0; // 對象的一個銷毀條件
    }

    // 活動對象
    @Override
    public void activateObject(PooledObject<SeatNum> pooledObject) throws Exception {
        System.out.println("【活動對象】初始化前剩余數量="+pooledObject.getObject().num);
//        pooledObject.getObject().num = 100;
//        System.out.println("【活動對象】初始化后剩余數量="+pooledObject.getObject().num);
    }

    // 停用(歸還)對象
    @Override
    public void passivateObject(PooledObject<SeatNum> pooledObject) throws Exception {
        System.out.println("【停用對象】數量="+pooledObject.getObject().num);

    }
}

2、對象類  

package com.zc.demo;

import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;

public class SeatNum {

    int num = 100;

    void doSomething() {
        System.out.println("引用前的座位數量:" + this.num);
        num -= 40;
        System.out.println("引用后的座位數量:" + this.num);
    }

    public static void main(String[] args) {
        GenericObjectPoolConfig genericObjectPoolConfig = new GenericObjectPoolConfig();
        genericObjectPoolConfig.setMaxTotal(5);
        genericObjectPoolConfig.setMinIdle(2);//最小空閑數量,也是默認初始化的數量
        genericObjectPoolConfig.setMaxIdle(2);
        genericObjectPoolConfig.setMinEvictableIdleTimeMillis(1000);
        genericObjectPoolConfig.setTestOnBorrow(true);// 引用對象后(對象已存在,且重復使用)調用驗證validateObject(常用)
//        genericObjectPoolConfig.setTestOnReturn(true);// 停用對象前(對象已存在)調用驗證validateObject(常用)
//        genericObjectPoolConfig.setTestOnCreate(true);// 創建對象(對象未存在)時驗證validateObject(極少情況采用)
//        genericObjectPoolConfig.setTestWhileIdle(true);// 對象一直空閑時驗證validateObject(極少情況采用)
        GenericObjectPool<SeatNum> objectPool = new GenericObjectPool<>(new SeatNumFactory(), genericObjectPoolConfig);

        SeatNum powerBank = null;
        for (int i = 0; i < 10; i++) {
            try {
                objectPool.preparePool();// 默認初始化
                System.out.println("====================【" + i + "】===================");
                powerBank = objectPool.borrowObject();
                powerBank.doSomething();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (powerBank != null) {
                    objectPool.returnObject(powerBank);
                }
            }
        }
    }


}

 

對象池的優點:

(1)復用池中對象

(2)消除創建對象、回收對象 所產生的內存開銷、cpu開銷以及(若跨網絡)產生的網絡開銷.

 

對象池的缺點:

(1)現在Java的對象分配操作不比c語言的malloc調用慢, 對於輕中量級的對象, 分配/釋放對象的開銷可以忽略不計;

(2)並發環境中, 多個線程可能(同時)需要獲取池中對象, 進而需要在堆數據結構上進行同步或者因為鎖競爭而產生阻塞, 這種開銷要比創建銷毀對象的開銷高數百倍;

(3)由於池中對象的數量有限, 勢必成為一個可伸縮性瓶頸;

(4)很難正確的設定對象池的大小, 如果太小則起不到作用, 如果過大, 則占用內存資源高, 可以起一個線程定期掃描分析, 將池壓縮到一個合適的尺寸以節約內存,但為了獲得不錯的分析結果, 在掃描期間可能需要暫停復用以避免干擾(造成效率低下), 或者使用非常復雜的算法策略(增加維護難度);

(5)設計和使用對象池容易出錯, 設計上需要注意狀態同步, 這是個難點, 使用上可能存在忘記歸還(就像c語言編程忘記free一樣), 重復歸還(可能需要做個循環判斷一下是否池中存在此對象, 這也是個開銷), 歸還后仍舊使用對象(可能造成多個線程並發使用一個對象的情況)等問題;

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM