目录
一、什么是享元模式
二、享元模式的角色
三、享元模式的典型应用场景
四、享元模式在ThreadPoolExecutor中的应用
1. 享元对象(Flyweight)- 工作线程(Worker)
2. 享元工厂(Flyweight Factory)- ThreadPoolExecutor
3. 外部状态(Extrinsic State)- 任务(Runnable)
4. 上下文(Context)- 任务执行的环境
一、什么是享元模式
享元模式(Flyweight Pattern)是一种结构型设计模式,其核心思想是使用共享的方式来高效地管理大量细粒度的对象。享元模式的主要目的是减少内存消耗,通过共享对象来减少创建对象的数量。这种模式特别适用于系统中存在大量相似或相同的对象时,通过共享这些对象可以减少内存占用和提高性能。
二、享元模式的角色
-
享元对象(Flyweight):享元对象是享元模式的核心,它代表了可以被共享的最小单位。享元对象包含内部状态(intrinsic state),这些状态是不变的,并且通常在享元对象创建时就确定下来。享元对象不存储外部状态(extrinsic state),外部状态通常由客户端在需要时提供。
-
享元工厂(Flyweight Factory):享元工厂负责创建和管理享元对象。它确保享元对象被适当地共享,并且当需要享元对象时,工厂会提供一个现有的实例或创建一个新的实例。享元工厂还负责管理享元对象的生命周期,包括对象的创建、存储和销毁。
-
上下文(Context)(可选):上下文角色不是享元模式的标准部分,但在某些实现中可能会出现。上下文角色负责将享元对象与外部状态结合起来,以便在享元对象执行操作时提供完整的环境。这有助于隐藏享元对象和外部状态之间的耦合,使得享元对象可以专注于其内部状态和行为。
三、享元模式的典型应用场景
-
线程池:线程池中的线程对象可以被视为享元对象,被多个任务共享使用,从而避免了频繁创建和销毁线程的开销。
-
数据库连接池:数据库连接是一种资源,通过使用享元模式,可以共享已经创建的数据库连接对象,避免频繁创建和销毁数据库连接,提高数据库访问效率。
-
对象池:对象池是一种特殊的缓存系统,用于管理对象的生命周期。通过使用对象池技术,可以预先创建一定数量的对象,并在需要时将它们分配出去,使用完毕后再将它们回收回来重新利用。这样可以避免频繁地创建和销毁对象,从而提高系统性能。
-
字符串池:Java中的字符串常量池就是使用享元模式的典型示例。当多个字符串具有相同的值时,它们可以共享同一个字符串对象,从而节省了内存空间。
四、享元模式在ThreadPoolExecutor中的应用
1. 享元对象(Flyweight)- 工作线程(Worker)
在ThreadPoolExecutor
中,享元对象是工作线程。每个工作线程可以执行多个任务,任务完成后,线程不会销毁,而是返回线程池中等待执行下一个任务。
final class Worker extends AbstractQueuedSynchronizer implements Runnable {
// 省略其他代码...
}
Worker
类是ThreadPoolExecutor
中的核心,它继承自AbstractQueuedSynchronizer
并实现了Runnable
接口。每个Worker
对象代表一个线程,可以反复执行多个任务。
2. 享元工厂(Flyweight Factory)- ThreadPoolExecutor
ThreadPoolExecutor
本身充当享元工厂的角色,负责创建和维护工作线程(享元对象)。
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
// 省略其他代码...
}
构造函数初始化线程池的基本属性,如核心线程数、最大线程数、工作队列等。
3. 外部状态(Extrinsic State)- 任务(Runnable)
在ThreadPoolExecutor
中,外部状态是提交给线程池执行的任务。每个任务都是独立的,工作线程(享元对象)执行这些任务时会使用它们。
executor.execute(new Runnable() {
public void run() {
// 任务代码
}
});
4. 上下文(Context)- 任务执行的环境
在ThreadPoolExecutor
的上下文中,上下文可以被视为Worker
对象本身。Worker
对象不仅包含了线程(Thread),还包含了要执行的任务(firstTask
)。当Worker
对象执行任务时,它实际上就是在提供执行环境,即上下文。Worker
对象从任务队列中获取任务并执行,这个过程中Worker
对象就是享元对象与外部状态(任务)之间的桥梁。