【Java设计模式】对象池模式

一、概述

Java中的对象池设计模式管理一组可重用的对象,通过回收对象而不是反复创建和销毁它们来优化内存管理和应用程序性能。

二、详细解释及实际示例

  1. 实际示例
    • 想象一个图书馆,它有数量有限的自习室,这些自习室经常被需求。而不是每个学生在需要时都建造自己的自习室,图书馆管理着一个可用自习室的池。当学生需要一个自习室时,他们从池中借出一个。使用完后,他们将自习室归还到池中供其他人使用。这确保了自习室得到有效利用,而无需每次都建造新的自习室,从而节省了时间和资源,类似于对象池模式在软件中管理昂贵对象的重用。
  2. 通俗解释
    • 对象池管理一组实例,而不是按需创建和销毁它们。
  3. 维基百科说
    • 对象池模式是一种软件创建设计模式,它使用一组初始化的对象随时准备使用——一个“池”——而不是按需分配和销毁它们。

三、Java中对象池模式的编程示例

在我们的战争游戏中,我们需要使用猛犸象,这是一种巨大而神秘的野兽,但问题是它们的创建成本非常高。解决方案是创建一个它们的池,跟踪哪些正在使用,并重新使用这些实例而不是丢弃它们。
这里是基本的Oliphaunt类。这些巨兽的创建成本非常高。

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);
    }
}

接下来,我们展示ObjectPool,更具体地说是OliphauntPool

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中使用对象池模式

当以下情况时使用对象池模式:

  1. 您需要频繁创建和销毁对象,导致高资源分配和释放成本。
  2. 对象的创建和维护成本高昂(例如,数据库连接、线程池)。
  3. 需要控制固定数量的对象,如在连接池中。
  4. 对象重用可以显著提高系统性能和资源管理。

五、对象池模式在Java中的实际应用

  1. Java应用程序中的数据库连接池。
  2. Java并发编程中的线程池。
  3. 网络应用程序中的套接字连接池。
  4. 游戏开发中频繁创建和销毁的游戏对象的对象池。

六、对象池模式的好处和权衡

好处:

  1. 提高性能:减少对象创建和垃圾回收的开销。
  2. 资源管理:控制实例的数量,减少资源争用并限制资源使用。
  3. 可扩展性:通过重用固定数量的对象,允许应用程序处理更多请求。

权衡:

  1. 复杂性:增加了代码库的复杂性,需要仔细管理池。
  2. 线程安全:需要仔细处理对池的并发访问,引入潜在的同步问题。
  3. 初始化成本:池的初始创建可能是资源密集型的。

七、源码下载

对象池模式示例代码下载

Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐