目录

  1. 什么是对象池
  2. 对象池的应用场景
  3. 核心设计思想
  4. 手写一个简单对象池
  5. Apache Commons Pool2
  6. Netty 对象池
  7. 最佳实践

在这里插入图片描述

1. 什么是对象池

定义

对象池 (Object Pool) 是一种创建型设计模式,用于管理一组预先初始化好的对象,使用时从池中获取,用完后归还而不是销毁。

为什么需要对象池?

问题对象池解决
对象创建开销大预创建,复用
创建时间长从池中取,立即可用
内存碎片减少 GC
限制资源使用控制最大数量

生活中的类比

1. 借钥匙
2. 分配
3. 使用
4. 用完归还

用户

前台

储物柜

使用中


2. 对象池的应用场景

2.1 适合使用的场景

适合使用对象池

数据库连接
Connection Pool

线程池
Thread Pool

网络连接
HTTP/gRPC

大对象/复杂对象
XML解析器/加密器

高性能场景
低延迟/高吞吐

数据库连接 (Connection Pool)

  • 创建连接耗时 (TCP 握手、认证等)
  • 连接数有限

线程池 (Thread Pool)

  • 线程创建开销大
  • 避免无限创建线程

网络连接 (HTTP / gRPC)

  • 连接建立耗时
  • 可复用连接

大对象 / 复杂对象

  • 初始化成本高
  • 例如:XML 解析器、加密解密器

高性能场景

  • 低延迟要求
  • 高吞吐量要求

2.2 不适合使用的场景

不适合使用对象池

轻量对象
String/StringBuilder

使用频率极低

线程安全要求极高
难以实现

轻量对象

  • 例如:String、StringBuilder
  • 对象本身比池管理开销还小

使用频率极低

  • 维护池的成本 > 收益

线程安全要求极高,难以实现


3. 核心设计思想

3.1 对象池状态机

预创建/归还

borrowObject

returnObject (成功)

invalidateObject (异常)

清理/关闭

创建

空闲

使用中

销毁

验证失败也会
直接销毁

3.2 核心接口

使用

«interface»

PooledObjectFactory<T>

+create() : T

+destroy(T obj) : void

+validate(T obj) : boolean

+activate(T obj) : void

+passivate(T obj) : void

«interface»

ObjectPool<T>

+borrowObject() : T

+returnObject(T obj) : void

+invalidateObject(T obj) : void

+getNumIdle() : int

+getNumActive() : int

+close() : void

// 对象工厂 - 负责对象的生命周期管理
interface PooledObjectFactory<T> {
    T create();              // 创建对象
    void destroy(T obj);     // 销毁对象
    boolean validate(T obj); // 验证对象是否健康
    void activate(T obj);    // 激活对象(借出前)
    void passivate(T obj);   // 钝化对象(归还后)
}

// 对象池
interface ObjectPool<T> {
    T borrowObject();        // 从池中借一个对象
    void returnObject(T obj); // 归还对象
    void invalidateObject(T obj); // 废弃无效对象
    int getNumIdle();        // 空闲对象数
    int getNumActive();      // 活跃对象数
    void close();            // 关闭池
}

3.3 借对象流程图

有效

无效


未达上限

不能
已达上限

超时

有空闲

开始 borrowObject

池中
有空闲?

验证
是否有效?

激活对象

返回对象

废弃对象

能否
创建新对象?

创建新对象

激活

等待
空闲对象?

抛出异常


4. 手写一个简单对象池

4.1 版本 1: 最基础的实现

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;

public class SimpleObjectPool<T> {

    private final BlockingQueue<T> pool;
    private final PooledObjectFactory<T> factory;
    private final int maxTotal;
    private final AtomicInteger createdCount = new AtomicInteger(0);

    public SimpleObjectPool(PooledObjectFactory<T> factory, int maxTotal) {
        this.factory = factory;
        this.maxTotal = maxTotal;
        this.pool = new LinkedBlockingQueue<>(maxTotal);
    }

    // 借对象
    public T borrowObject() throws Exception {
        T obj = pool.poll();
        if (obj != null) {
            if (factory.validate(obj)) {
                factory.activate(obj);
                return obj;
            } else {
                invalidateObject(obj);
            }
        }

        // 池里没有,尝试创建
        if (createdCount.get() < maxTotal) {
            synchronized (this) {
                if (createdCount.get() < maxTotal) {
                    T newObj = factory.create();
                    createdCount.incrementAndGet();
                    factory.activate(newObj);
                    return newObj;
                }
            }
        }

        // 达到上限,阻塞等待
        return pool.take();
    }

    // 归还对象
    public void returnObject(T obj) {
        if (obj == null) {
            return;
        }

        try {
            if (factory.validate(obj)) {
                factory.passivate(obj);
                pool.offer(obj);
            } else {
                invalidateObject(obj);
            }
        } catch (Exception e) {
            invalidateObject(obj);
        }
    }

    // 废弃对象
    public void invalidateObject(T obj) {
        if (obj == null) {
            return;
        }

        try {
            factory.destroy(obj);
        } finally {
            createdCount.decrementAndGet();
        }
    }

    public int getNumIdle() {
        return pool.size();
    }

    public int getNumActive() {
        return createdCount.get() - pool.size();
    }

    public void close() {
        pool.forEach(this::invalidateObject);
        pool.clear();
    }

    // 工厂接口
    public interface PooledObjectFactory<T> {
        T create() throws Exception;
        void destroy(T obj) throws Exception;
        boolean validate(T obj);
        void activate(T obj) throws Exception;
        void passivate(T obj) throws Exception;
    }
}

4.2 使用示例

// 示例:一个昂贵的对象
class ExpensiveObject {
    private String id;

    public ExpensiveObject(String id) {
        this.id = id;
        System.out.println("✅ 创建对象: " + id + " (这很慢...)");
        try {
            Thread.sleep(1000); // 模拟创建耗时
        } catch (InterruptedException e) {}
    }

    public void doWork() {
        System.out.println("   对象 " + id + " 正在工作...");
    }

    public String getId() {
        return id;
    }
}

public class SimplePoolDemo {
    public static void main(String[] args) throws Exception {
        // 创建工厂
        SimpleObjectPool.PooledObjectFactory<ExpensiveObject> factory = 
            new SimpleObjectPool.PooledObjectFactory<>() {
                private int counter = 0;

                @Override
                public ExpensiveObject create() {
                    return new ExpensiveObject("Obj-" + (++counter));
                }

                @Override
                public void destroy(ExpensiveObject obj) {
                    System.out.println("❌ 销毁对象: " + obj.getId());
                }

                @Override
                public boolean validate(ExpensiveObject obj) {
                    return true; // 简化,总是有效
                }

                @Override
                public void activate(ExpensiveObject obj) {
                    System.out.println("▶️  激活对象: " + obj.getId());
                }

                @Override
                public void passivate(ExpensiveObject obj) {
                    System.out.println("⏸️  钝化对象: " + obj.getId());
                }
            };

        // 创建池,最大 2 个对象
        SimpleObjectPool<ExpensiveObject> pool = 
            new SimpleObjectPool<>(factory, 2);

        System.out.println("=== 第一次借对象 ===");
        ExpensiveObject obj1 = pool.borrowObject();
        obj1.doWork();

        System.out.println("\n=== 第二次借对象 ===");
        ExpensiveObject obj2 = pool.borrowObject();
        obj2.doWork();

        System.out.println("\n=== 归还 obj1 ===");
        pool.returnObject(obj1);

        System.out.println("\n=== 第三次借对象 (应该复用 obj1) ===");
        ExpensiveObject obj3 = pool.borrowObject();
        obj3.doWork();

        System.out.println("\n=== 状态统计 ===");
        System.out.println("空闲: " + pool.getNumIdle());
        System.out.println("活跃: " + pool.getNumActive());

        // 归还
        pool.returnObject(obj2);
        pool.returnObject(obj3);

        // 关闭池
        pool.close();
    }
}

4.3 版本 2: 支持更多配置

ObjectPoolConfig

-int maxTotal

-int maxIdle

-int minIdle

-Duration maxWaitDuration

-Duration timeBetweenEvictionRuns

-boolean testOnBorrow

-boolean testOnReturn

-boolean testWhileIdle

+...

+getMaxTotal() : int

+setMaxTotal(int) : void

import java.time.Duration;

public class ObjectPoolConfig {
    private int maxTotal = 8;           // 最大总数
    private int maxIdle = 8;            // 最大空闲
    private int minIdle = 0;            // 最小空闲
    private Duration maxWaitDuration = Duration.ofSeconds(10); // 最大等待时间
    private Duration timeBetweenEvictionRuns = Duration.ofMinutes(1); // 清理间隔
    private boolean testOnBorrow = true;    // 借时验证
    private boolean testOnReturn = false;   // 还时验证
    private boolean testWhileIdle = true;   // 空闲时验证

    // getters and setters...
}

5. Apache Commons Pool2 (业界标准)

5.1 Commons Pool2 架构

Apache Commons Pool2

borrow/return

create/destroy

包装

持有

用户代码

GenericObjectPool

PooledObjectFactory

PooledObject
包装层

业务对象

5.2 引入依赖

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
    <version>2.12.0</version>
</dependency>

5.3 使用示例

import org.apache.commons.pool2.BasePooledObjectFactory;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;

// 1. 定义工厂
class ExpensiveObjectFactory extends BasePooledObjectFactory<ExpensiveObject> {

    private int counter = 0;

    @Override
    public ExpensiveObject create() {
        return new ExpensiveObject("Obj-" + (++counter));
    }

    @Override
    public PooledObject<ExpensiveObject> wrap(ExpensiveObject obj) {
        return new DefaultPooledObject<>(obj);
    }

    @Override
    public void destroyObject(PooledObject<ExpensiveObject> p) {
        System.out.println("❌ 销毁: " + p.getObject().getId());
    }

    @Override
    public boolean validateObject(PooledObject<ExpensiveObject> p) {
        return true;
    }

    @Override
    public void activateObject(PooledObject<ExpensiveObject> p) {
        System.out.println("▶️  激活: " + p.getObject().getId());
    }

    @Override
    public void passivateObject(PooledObject<ExpensiveObject> p) {
        System.out.println("⏸️  钝化: " + p.getObject().getId());
    }
}

// 2. 使用池
public class CommonsPoolDemo {
    public static void main(String[] args) throws Exception {
        // 配置
        GenericObjectPoolConfig<ExpensiveObject> config = 
            new GenericObjectPoolConfig<>();
        config.setMaxTotal(10);
        config.setMaxIdle(5);
        config.setMinIdle(1);
        config.setMaxWait(Duration.ofSeconds(5));
        config.setTestOnBorrow(true);

        // 创建池
        ExpensiveObjectFactory factory = new ExpensiveObjectFactory();
        GenericObjectPool<ExpensiveObject> pool = 
            new GenericObjectPool<>(factory, config);

        // 使用
        ExpensiveObject obj = pool.borrowObject();
        try {
            obj.doWork();
        } finally {
            pool.returnObject(obj);
        }

        pool.close();
    }
}

6. Netty 对象池 (高性能场景)

get

get

get

线程本地存储

线程本地存储

线程本地存储

recycle

recycle

线程 1

Recycler

线程 2

线程 3

ThreadLocal
对象栈

ThreadLocal
对象栈

ThreadLocal
对象栈

对象 1

对象 2

Netty 有自己的轻量级对象池实现,用于频繁分配的对象 (如 ByteBuf)。

6.1 Recycler

import io.netty.util.Recycler;

class MyObject {
    private static final Recycler<MyObject> RECYCLER = new Recycler<>() {
        @Override
        protected MyObject newObject(Handle<MyObject> handle) {
            return new MyObject(handle);
        }
    };

    private final Recycler.Handle<MyObject> handle;

    private MyObject(Recycler.Handle<MyObject> handle) {
        this.handle = handle;
    }

    public static MyObject newInstance() {
        return RECYCLER.get();
    }

    public void recycle() {
        handle.recycle(this);
    }

    // 业务数据
    private String data;
    public void setData(String data) { this.data = data; }
    public String getData() { return data; }
}

// 使用
public class NettyRecyclerDemo {
    public static void main(String[] args) {
        MyObject obj = MyObject.newInstance();
        obj.setData("Hello");
        System.out.println(obj.getData());

        obj.recycle(); // 归还

        // 再次获取 (可能复用之前的对象)
        MyObject obj2 = MyObject.newInstance();
        System.out.println(obj2.getData()); // 可能还是 "Hello" (取决于实现)
    }
}

7. 最佳实践

7.1 调优参数

参数建议说明
maxTotal2-8 x CPU根据实际压测
maxIdle= maxTotal 或略小避免频繁创建销毁
minIdle1-2保持少量预热
maxWait不要太长避免无限等待

7.2 常见坑

常见错误

导致

导致

导致

忘记归还对象
try-finally

对象泄漏

归还后继续使用

并发问题

对象状态不清理

污染下一个使用者

忘记归还对象 → 泄漏

// 错误示范
ExpensiveObject obj = pool.borrowObject();
obj.doWork();
// 忘记 returnObject!

正确做法

ExpensiveObject obj = null;
try {
    obj = pool.borrowObject();
    obj.doWork();
} finally {
    if (obj != null) {
        pool.returnObject(obj);
    }
}

归还后继续使用 → 并发问题

对象状态没有清理 → 污染下一个使用者

7.3 监控

监控指标

getNumActive
活跃数

getNumIdle
空闲数

borrow等待时间

对象创建频率

// 建议监控指标
- getNumActive()  // 活跃数
- getNumIdle()    // 空闲数
- borrow 等待时间
- 对象创建频率

总结

对象池
总结

核心思想

空间换时间

预创建 + 复用

控制资源用量

适用场景

数据库连接

线程池

网络连接

大对象

选型建议

生产用 Commons Pool2

高性能用 Netty Recycler

学习用自己手写

注意事项

一定用 try-finally

做好监控

防止泄漏

  • 对象池 = 空间换时间
  • 不是所有对象都需要池化
  • 推荐用 Apache Commons Pool2
  • 一定要用 try-finally 确保归还
  • 做好监控,防止泄漏

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐