跳转到内容

对象池

25% developed
来自维基教科书,开放的书籍,面向开放的世界

访问者 计算机科学设计模式
对象池
模型-视图-控制器

对象池模式使用一组已初始化的、随时可用的对象,而不是按需分配和销毁它们。池的客户端将从池中请求一个对象,并在返回的对象上执行操作。当客户端完成操作时,它会将对象(这是一种特定类型的工厂对象)返回池中,而不是销毁它。

在初始化类实例成本高、类实例化率高且任何时刻使用实例数量低的场景中,对象池可以提供显著的性能提升。当创建新对象(尤其是通过网络)可能需要可变时间时,池化对象可以在可预测的时间内获取。

然而,这些优势主要适用于那些在时间上昂贵的对象,例如数据库连接、套接字连接、线程和大型图形对象,例如字体或位图。在某些情况下,简单的对象池(不包含外部资源,只占用内存)可能效率低下,并可能降低性能。

处理空池

对象池采用三种策略之一来处理池中没有备用对象时的请求。

  1. 无法提供对象(并向客户端返回错误)。
  2. 分配一个新对象,从而增加池的大小。执行此操作的池通常允许您设置高水位标记(曾经使用的最大对象数)。
  3. 在多线程环境中,池可能会阻塞客户端,直到另一个线程将对象返回池。

陷阱

在编写对象池时,程序员必须小心确保返回池的对象状态重置为下一个使用对象的合理状态。如果没有观察到这一点,对象通常会处于客户端程序未预期的状态,并可能导致客户端程序失败。池负责重置对象,而不是客户端。充满处于危险过时状态的对象的池有时被称为对象污水池,并被视为反模式。

过时状态的存在并不总是问题;当过时状态的存在导致对象的行为发生改变时,它就会变得危险。例如,表示身份验证详细信息的对象如果在传递出去之前没有重置“成功身份验证”标志,可能会出现问题,因为它将表明用户已成功身份验证(可能是其他人),而他们还没有尝试身份验证。但是,如果您只是没有重置一些仅用于调试的值,例如最后使用的身份验证服务器的标识,它就可以正常工作。

对象重置不充分也可能导致信息泄露。如果对象包含机密数据(例如用户的信用卡号码),而这些数据在对象传递给新客户端之前没有清除,恶意或有错误的客户端可能会将数据泄露给未经授权的方。

如果池被多个线程使用,它可能需要防止并行线程并行获取和尝试重用同一对象的方法。如果池化对象是不可变的或线程安全的,则不需要这样做。

批评

一些出版物不建议在某些语言中使用对象池,例如 Java,特别是对于只使用内存而不包含外部资源的对象。反对者通常认为,在具有垃圾回收机制的现代语言中,对象分配相对较快;虽然运算符new只需要十条指令,但在池化设计中找到的经典new-delete对需要数百条指令,因为它执行更复杂的工作。此外,大多数垃圾回收器会扫描“活动”对象引用,而不是这些对象用于其内容的内存。这意味着任何数量的没有引用的“死亡”对象都可以以很小的代价丢弃。相比之下,保持大量“活动”但未使用的对象会延长垃圾回收的持续时间。在某些情况下,使用垃圾回收而不是直接管理内存的程序可能会运行得更快。

示例

在 .NET 基本类库中,有一些对象实现了这种模式。System.Threading.ThreadPool 被配置为具有预定义数量的线程来分配。当线程返回时,它们可用于其他计算。因此,人们可以使用线程,而无需支付创建和处置线程的成本。

Java 通过java.util.concurrent.ExecutorService和其他相关类支持线程池。执行器服务具有一定数量的“基本”线程,这些线程永远不会被丢弃。如果所有线程都很繁忙,服务会分配允许数量的额外线程,这些线程如果在一定时间内未使用,则会稍后被丢弃。如果不再允许使用更多线程,则任务可以放入队列。最后,如果此队列可能变得过长,它可以配置为挂起请求线程。

Clipboard

待办事项
添加更多插图。


访问者 计算机科学设计模式
对象池
模型-视图-控制器


您对该页面有任何问题吗?
在这里询问


在这本书上创建一个新页面


华夏公益教科书