apache.commons.pool2 使用指南

apache.commons.pool2 使用指南

为什么要使用池

创建对象耗时较长,多线程频繁调用等因素限制了我们不能每次使用时都重新创建对象,使用池化思想将对象放进池内,不同线程使用同一个池来获取对象,极大的减少每次业务的调用时间。

一个线程内多次使用这个对象所建立的连接。

使用场景

  • 数据库连接池:HikariCP、Druid
  • 自定义业务连接池:耗时的客户端连接远程服务端

如何使用

1、创建对象客户端

java 复制代码
package com.ncst.client.mcc;

import lombok.extern.slf4j.Slf4j;
import java.util.Objects;

/**
 * @Author: Lisy
 * @Description: MCC 操作工具类
 */
@Slf4j
public class MccClient {

    public MccClient() {
    }

    public void putMc(String key, String value) {
        if (Objects.isNull(key)) {
            throw new IllegalArgumentException("The key argument cannot be null");
        }
        log.info("{}=={}", key, value);
    }

    public String getMc(String key) {
        if (Objects.isNull(key)) {
            throw new IllegalArgumentException("The " + key + " argument cannot be null");
        }
        return "";
    }

}

2、创建池工厂类

java 复制代码
package com.ncst.client.mcc;

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

/**
 * @Author: Lisy
 * @Description: 对象池工厂
 */
public class MccClientFactory implements PooledObjectFactory<MccClient> {

    public MccClientFactory() {
    }

    @Override
    public PooledObject<MccClient> makeObject() {
        MccClient dccClient = new MccClient();
        return new DefaultPooledObject<>(dccClient);
    }

    @Override
    public void destroyObject(PooledObject<MccClient> p) {
        MccClient object = p.getObject();
        object.close();
    }

    @Override
    public boolean validateObject(PooledObject<MccClient> p) {
        // 验证对象是否可用的逻辑,如果需要
        return true;
    }

    @Override
    public void activateObject(PooledObject<MccClient> p) {
        // 激活对象的逻辑,如果需要
    }

    @Override
    public void passivateObject(PooledObject<MccClient> p) {
        // 钝化对象的逻辑,如果需要
    }

}

3、对象池管理类

用于管理保存的池对象,单例模式

shutdown 方法在不使用时关闭掉对应任务的所有池连接

java 复制代码
package com.ncst.client;

import com.ncst.client.mcc.MccClient;
import com.ncst.client.mcc.MccClientFactory;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;

import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Author: Lisy
 * @Description: 对象池管理
 */
public class MccClientPoolManager {
    private static volatile MccClientPoolManager INSTANCE;

    private MccClientPoolManager() {
    }

    public static MccClientPoolManager getInstance() {
        if (Objects.isNull(INSTANCE)) {
            synchronized (MccClientPoolManager.class) {
                if (Objects.isNull(INSTANCE)) {
                    INSTANCE = new MccClientPoolManager();
                }
            }
        }
        return INSTANCE;
    }

    /**
     * key-jobUuid, value-每一个任务池
     */
    private final ConcurrentHashMap<String, GenericObjectPool<MccClient>> POOL_MAP = new ConcurrentHashMap<>();

    public GenericObjectPool<MccClient> getPool(String jobId, GenericObjectPoolConfig<MccClient> poolConfig) {
        return POOL_MAP.computeIfAbsent(jobId, k -> new GenericObjectPool<>(new MccClientFactory(), poolConfig));
    }

    public void shutdown(String jobId) {
        GenericObjectPool<MccClient> dccClientGenericObjectPool = POOL_MAP.get(jobId);
        if (Objects.nonNull(dccClientGenericObjectPool)) {
            dccClientGenericObjectPool.close();
        }
    }
}

4、使用

通过多线程来模拟实际使用场景,如果使用默认poolConfig,那么最大池大小为8个,最多创建8个对象。

通过CountDownLatch 来等待所有任务完成

通过 MccClientPoolManager.getInstance().shutdown("key"); 来关闭池

"key" 可根据业务逻辑自行定义

java 复制代码
 public static void main(String[] args) throws InterruptedException {
        int num = 20;
        CountDownLatch latch = new CountDownLatch(num);
        for (int i = 0; i < num; i++) {
            int finalI = i;
            CompletableFuture.runAsync(() -> {
                try {
                    GenericObjectPool<MccClient> pool2 = MccClientPoolManager.getInstance()
                            .getPool("key", new GenericObjectPoolConfig<>());
                    MccClient mccClient = null;
                    try {
                        mccClient = pool2.borrowObject();
                        mccClient.putMc("" + finalI, "value" + finalI);
                    } finally {
                        if (Objects.nonNull(mccClient)) {
                            pool2.returnObject(mccClient);
                        }
                    }
                } catch (Exception e) {
                    logger.error(e.getMessage(), e);
                } finally {
                    latch.countDown();
                }

            });
        }
        latch.await();
        MccClientPoolManager.getInstance().shutdown("key");
    }

源码解析-create()

复制代码
510:private PooledObject<T> create() throws Exception
创建对象时锁住makeObjectCountLock,判断当前已创建对象是否大于设置的池大小,如果未超过则create==true

超过则判断已有的池大小是否为0,如果为0返回create==false,
不为0等待正在创建的对象,执行makeObjectCountLock.wait

create 为true则创建对象,执行 public PooledObject<T> makeObject()

创建完对象后判断是否为空,如果为空将已创建对象 cretaeCount--,并抛出异常

验证对象是否可用,如果不可用返回null,并cretaeCount--

在finally 中锁住 makeObjectCount lock,将makeObjectCount--,唤醒锁中所有等待的对象

将对象放入allObjects map中
相关推荐
Jackyzhe5 小时前
Apache Iceberg Variant 类型:v3 半结构化数据不再「二选一」
apache
Yeniden6 小时前
Java 后端从零到企业级:第1篇 Java 基础语法——变量、数据类型与运算符
java·开发语言·apache
盟道科技2 天前
电商小程序SKU数据模型设计:SPU、规格组合、库存与价格的工程实践
服务器·小程序·apache
A-刘晨阳2 天前
时序数据基础设施选型手册:Apache IoTDB 技术深度解析与性能实战
apache·iotdb
吴声子夜歌3 天前
ApacheCommons——commons-exec(外部进程与系统命令安全执行)
java·安全·apache
qetfw3 天前
Debian 部署 phpMyAdmin:Apache、PHP 与 MariaDB 管理界面配置
linux·debian·php·apache
吴声子夜歌3 天前
ApacheCommons——commons-compress(解压缩工具)
java·apache
吴声子夜歌3 天前
ApacheCommons——commons-math3(科学计算与线性代数)(一)
java·线性代数·算法·apache
吴声子夜歌3 天前
ApacheCommons——commons-configuration2(多数据源配置统一管理与热加载)
java·开发语言·算法·apache
W658034194 天前
Meta Muse Glimmer 30B开源深度拆解:Apache 2.0+投机解码,24GB显卡跑本地Agent
ai·开源·大模型·apache·deepseek