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一样), 重复归还(可能需要做个循环判断一下是否池中存在此对象, 这也是个开销), 归还后仍旧使用对象(可能造成多个线程并发使用一个对象的情况)等问题;

原文地址:https://www.cnblogs.com/tianchao/p/13809062.html