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中
相关推荐
迦蓝叶1 天前
Apache Jena SPARQL 查询完全指南:入门与实战案例
apache·知识图谱·图搜索算法·三元组·jena·sparql·图查询
向上的车轮2 天前
数据中台工作流编排引擎:Apache Airflow
apache
雾迟sec2 天前
Web安全-文件上传漏洞-黑白名单及其它绕过思路(附思维导图)
javascript·安全·web安全·网络安全·apache·安全威胁分析
yumgpkpm2 天前
CMP(类Cloudera CDP 7.3 404版华为泰山Kunpeng)和Apache Doris的对比
大数据·hive·hadoop·spark·apache·hbase·cloudera
zhangkaixuan4562 天前
Apache Paimon 查询全流程深度分析
java·apache·paimon
A-刘晨阳2 天前
时序数据库选型指南:从大数据视角切入,聚焦 Apache IoTDB
大数据·apache·时序数据库·iotdb
迦蓝叶3 天前
使用 Apache Jena 构建 Java 知识图谱
java·apache·知识图谱·图搜索·关系查询·关系推理
zhangkaixuan4563 天前
Apache Paimon 写入流程
java·大数据·apache·paimon
DolphinScheduler社区3 天前
Apache DolphinScheduler 3.3.2 正式发布!性能与稳定性有重要更新
大数据·开源·apache·任务调度·海豚调度·发版
SeaTunnel3 天前
Apache SeaTunnel 支持 Metalake 开发了!避免任务配置敏感信息暴露
大数据·开源·apache·个人开发·数据集成·seatunnel·看开源之夏