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

  • 相关阅读:
    Centos下安装Redis
    Web框架的本质
    DOM Event
    HTML DOM
    JavaScript运算符
    JavaScript基础
    开发中常用的插件与框架
    selector模块
    IO模型(阻塞、非阻塞、多路复用与异步)
    事件驱动模型
  • 原文地址:https://www.cnblogs.com/tianchao/p/13809062.html
Copyright © 2020-2023  润新知