Java 中的对象池模式:使用可复用对象管理提升性能
大约 3 分钟
也称为
- 资源池
对象池设计模式的意图
Java 中的对象池设计模式管理一个可复用对象的池,通过循环使用对象而不是重复创建和销毁它们,来优化内存管理和应用程序性能。
对象池模式的详细说明以及现实世界中的例子
现实世界的例子
想象一个图书馆,它有有限数量的学习室,而且经常有人需要使用。图书馆管理一个可用的学习室池,而不是让每个学生在需要的时候都建造自己的学习室。当学生需要学习室时,他们从池中借用一个。用完后,他们将学习室归还到池中供其他人使用。这确保了学习室的有效利用,而无需每次都建造新的学习室,从而节省了时间和资源。这类似于对象池模式在软件中管理昂贵对象的复用方式。
通俗来说
对象池管理一组实例,而不是按需创建和销毁它们。
维基百科说
对象池模式是一种软件创建型设计模式,它使用一组已经初始化好的随时可用的对象(一个“池”),而不是按需分配和销毁它们。
Java 中对象池模式的编程示例
在我们的战争游戏中,我们需要使用巨象,这些是巨大而神秘的野兽,但问题是它们非常昂贵。解决方案是创建一个池,跟踪哪些巨象正在使用,而不是丢弃它们,而是复用这些实例。
这是基本的 巨象
类。这些巨象非常昂贵。
public class Oliphaunt {
private static final AtomicInteger counter = new AtomicInteger(0);
@Getter
private final int id;
public Oliphaunt() {
id = counter.incrementAndGet();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
LOGGER.error("Error occurred: ", e);
}
}
@Override
public String toString() {
return String.format("Oliphaunt id=%d", id);
}
}
接下来,我们介绍 对象池
,更具体地说是 巨象池
。
public abstract class ObjectPool<T> {
private final Set<T> available = new HashSet<>();
private final Set<T> inUse = new HashSet<>();
protected abstract T create();
public synchronized T checkOut() {
if (available.isEmpty()) {
available.add(create());
}
var instance = available.iterator().next();
available.remove(instance);
inUse.add(instance);
return instance;
}
public synchronized void checkIn(T instance) {
inUse.remove(instance);
available.add(instance);
}
@Override
public synchronized String toString() {
return String.format("Pool available=%d inUse=%d", available.size(), inUse.size());
}
}
public class OliphauntPool extends ObjectPool<Oliphaunt> {
@Override
protected Oliphaunt create() {
return new Oliphaunt();
}
}
最后,我们介绍如何使用池。
public static void main(String[] args) {
var pool = new OliphauntPool();
LOGGER.info(pool.toString());
var oliphaunt1 = pool.checkOut();
String checkedOut = "Checked out {}";
LOGGER.info(checkedOut, oliphaunt1);
LOGGER.info(pool.toString());
var oliphaunt2 = pool.checkOut();
LOGGER.info(checkedOut, oliphaunt2);
var oliphaunt3 = pool.checkOut();
LOGGER.info(checkedOut, oliphaunt3);
LOGGER.info(pool.toString());
LOGGER.info("Checking in {}", oliphaunt1);
pool.checkIn(oliphaunt1);
LOGGER.info("Checking in {}", oliphaunt2);
pool.checkIn(oliphaunt2);
LOGGER.info(pool.toString());
var oliphaunt4 = pool.checkOut();
LOGGER.info(checkedOut, oliphaunt4);
var oliphaunt5 = pool.checkOut();
LOGGER.info(checkedOut, oliphaunt5);
LOGGER.info(pool.toString());
}
程序输出
21:21:55.126 [main] INFO com.iluwatar.object.pool.App -- Pool available=0 inUse=0
21:21:56.130 [main] INFO com.iluwatar.object.pool.App -- Checked out Oliphaunt id=1
21:21:56.132 [main] INFO com.iluwatar.object.pool.App -- Pool available=0 inUse=1
21:21:57.137 [main] INFO com.iluwatar.object.pool.App -- Checked out Oliphaunt id=2
21:21:58.143 [main] INFO com.iluwatar.object.pool.App -- Checked out Oliphaunt id=3
21:21:58.145 [main] INFO com.iluwatar.object.pool.App -- Pool available=0 inUse=3
21:21:58.145 [main] INFO com.iluwatar.object.pool.App -- Checking in Oliphaunt id=1
21:21:58.145 [main] INFO com.iluwatar.object.pool.App -- Checking in Oliphaunt id=2
21:21:58.146 [main] INFO com.iluwatar.object.pool.App -- Pool available=2 inUse=1
21:21:58.146 [main] INFO com.iluwatar.object.pool.App -- Checked out Oliphaunt id=2
21:21:58.146 [main] INFO com.iluwatar.object.pool.App -- Checked out Oliphaunt id=1
21:21:58.147 [main] INFO com.iluwatar.object.pool.App -- Pool available=0 inUse=3
何时在 Java 中使用对象池模式
在以下情况下使用对象池模式
- 你需要频繁创建和销毁对象,导致高资源分配和释放成本。
- 创建和维护对象非常昂贵(例如数据库连接、线程池)。
- 需要控制固定数量的对象,例如连接池。
- 对象复用可以显著提高系统性能和资源管理。
Java 中对象池模式的现实世界应用
- Java 应用程序中的数据库连接池。
- Java 并发编程中的线程池。
- 网络应用程序中的套接字连接池。
- 游戏开发中对象池,用于频繁创建和销毁的游戏对象。
对象池模式的优缺点
优点
- 性能提升:减少了对象创建和垃圾回收的开销。
- 资源管理:控制实例数量,减少资源争用,限制资源使用。
- 可扩展性:允许应用程序通过复用固定数量的对象来处理更多请求。
缺点
- 复杂性:增加了代码库的复杂性,需要仔细管理池。
- 线程安全:需要仔细处理对池的并发访问,可能引入同步问题。
- 初始化成本:池的初始创建可能占用大量资源。