前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【设计模式】-创建型模式-第2章第5讲-【对象池模式】

【设计模式】-创建型模式-第2章第5讲-【对象池模式】

作者头像
跟着飞哥学编程
发布2022-12-02 15:51:33
4180
发布2022-12-02 15:51:33
举报

目录

1、对象池模式的定义

1.1、先来看看百度百科的定义

1.2、 对象池模式就是单例模式加享元模式

2、为什么要用对象池模式

2.1、原因

2.2、解决方案

3、对象池模式示例代码

4、对象池模式的应用场景

 5、对象池模式的优缺点

5.1、优点

5.2、缺点

 6、结语


1、对象池模式的定义

1.1、先来看看百度百科的定义

对象池模式 (The Object Pool Pattern) 是单例模式的一个变种,它提供了获取一系列相同对象实例的入口。当你需要对象来代表一组可替代资源的时候就变的很有用,每个对象每次可以被一个组件使用。


1.2、 对象池模式就是单例模式加享元模式

对象池模式(Object Pool Pattern),是创建型设计模式的一种,将对象预先创建并初始化后放入对象池中,对象提供者就能利用已有的对象来处理请求,减少频繁创建对象所占用的内存空间和初始化时间。一个对象池包含一组已经初始化并且可以使用的对象,可以在有需求时创建和销毁对象。对象池的用户可以从池子中取得对象,对其进行操作处理,并在不需要时归还给池子而非直接销毁。对象池是一个特殊的工厂对象,对象池模式就是单例模式加享元模式

对象池模式和享元模式的最大区别在于:

对象池模式中会多一个回收对象重复利用的方法。所以,对象池模式应该是享元模式更加具体的一个应用场景。相当于先将对象从对象池中借出,用完之后再还回去,以此保证有限资源的重复利用。 

 了解了对象池模式的定义,接下来,咱们就该思考为什么要用对象池模式。 用对象池模式的好处是什么以及它的弊端。

2、为什么要用对象池模式

2.1、原因

我们都知道对象的实例化是最耗性能的操作之一,这在过去是个大问题,现在不用再过分关注它。但是当我们处理封装外部资源的对象(例如数据库连接)时,对象的创建操作则会耗费很多资源。

2.2、解决方案

 解决方案就是重用和共享这些创建成本高昂的对象,这就是我们讲到的对象池模式。先来看看它的类图结构,如下图 2-1。

 图 2-1 

对象池模式中使用的类如下所示:

  • ResourcePool (资源池类):用于封装逻辑的类。用来保存和管理资源列表。
  • Resource(资源类):用于封装特定资源的类。资源类通常被资源池类引用,因此只要资源池不重新分配,它们就永远不会被回收。
  • Client(客户端类):使用资源的类。

当客户需要新资源时,会向资源池类申请,资源池类检查后获取第一个可用资源并将其返回给客户端。

客户端使用完资源后会进行资源释放,资源会重新回到资源池以便重复使用。

3、对象池模式示例代码

ObjectPool.java 文件代码如下:

代码语言:javascript
复制
package com.zhaoyanfei.designpattern.objectPoolPattern;

import java.util.Enumeration;
import java.util.Vector;

/**
 * 对象池
 * @Date 2022年10月4日
 * @author zhaoYanFei
 *
 */
public class ObjectPool {

	private int numObjects = 10; // 对象池的大小 
	private int maxObjects = 50; // 对象池最大的大小 
	private Vector<PooledObject> objects = null; //存放对象池中对象的向量(PooledObject类型) 
	
	public ObjectPool() {
		
	}
	
	/*** 创建一个对象池***/ 
	public synchronized void createPool(){ 
		// 确保对象池没有创建。如果创建了,保存对象的向量 objects 不会为空 
		if (objects != null) { 
			return; // 如果己经创建,则返回 
		}
		// 创建保存对象的向量 , 初始时有 0 个元素 
		objects = new Vector<PooledObject>(); 
		// 根据 numObjects 中设置的值,循环创建指定数目的对象 
		for (int x = 0; x < numObjects; x++) {
			if ((objects.size() == 0)&&this.objects.size() <this.maxObjects) { 
				Object obj = new Object(); 
				objects.addElement(new PooledObject(obj)); 
			}
		}
	}
	/**
	 * 获取对象
	 * @return
	 */
	public synchronized Object getObject(){
		// 确保对象池己被创建 
		if (objects == null) { 
			return null; // 对象池还没创建,则返回 null 
		}
		Object conn = getFreeObject(); // 获得一个可用的对象 
		// 如果目前没有可以使用的对象,即所有的对象都在使用中 
		while (conn == null) {
			wait(250); 
			conn = getFreeObject(); // 重新再试,直到获得可用的对象,如果 
			// getFreeObject() 返回的为 null,则表明创建一批对象后也不可获得可用对象 
		} 
		return conn;// 返回获得的可用的对象 
	}
	/** 
	* 本函数从对象池对象 objects 中返回一个可用的的对象 
	* 如果当前没有可用的对象,则创建几个对象,并放入对象池中。 
	* 如果创建后,所有的对象都在使用中,则返回 null 
	*/ 
	private Object getFreeObject(){
		// 从对象池中获得一个可用的对象
		Object obj = findFreeObject();
		if (obj == null) {
			createPool();//如果目前对象池中没有可用的对象,创建一些对象 
			// 重新从池中查找是否有可用对象
			obj = findFreeObject();
			// 如果创建对象后仍获得不到可用的对象,则返回 null
			if (obj == null) {
				return null;
			}
		}
		return obj;
	}
	/** 
	* 查找对象池中所有的对象,查找一个可用的对象, 
	* 如果没有可用的对象,返回 null 
	*/ 
	private Object findFreeObject(){
		Object obj = null;
		PooledObject pObj = null;
		// 获得对象池向量中所有的对象 
		Enumeration enumerate = objects.elements();
		// 遍历所有的对象,看是否有可用的对象
		while (enumerate.hasMoreElements()) {
			pObj = (PooledObject) enumerate.nextElement(); 
			// 如果此对象不忙,则获得它的对象并把它设为忙 
			if (!pObj.isBusy()) { 
				obj = pObj.getObject(); 
				pObj.setBusy(true); 
			}
		}
		return obj;// 返回找到到的可用对象 
	}
	/** 
	* 此函数返回一个对象到对象池中,并把此对象置为空闲。 
	* 所有使用对象池获得的对象均应在不使用此对象时返回它。 
	*/ 
	public void returnObject(Object obj) { 
		// 确保对象池存在,如果对象没有创建(不存在),直接返回 
		if (objects == null) {
			return;
		}
		PooledObject pObj = null;
		Enumeration enumerate = objects.elements();
		// 遍历对象池中的所有对象,找到这个要返回的对象
		while (enumerate.hasMoreElements()) { 
			pObj = (PooledObject) enumerate.nextElement(); 
			// 先找到对象池中的要返回的对象
			if (obj == pObj.getObject()) {
				// 找到了 , 设置此对象为空闲状态
				pObj.setBusy(false); 
				break;
			} 
		}
	}
	/** 
	* 关闭对象池中所有的对象,并清空对象池。
	*/ 
	public synchronized void closeObjectPool() { 
		// 确保对象池存在,如果不存在,返回 
		if (objects == null) {
			return; 
		} 
		PooledObject pObj = null;
		Enumeration enumerate = objects.elements();
		while (enumerate.hasMoreElements()) {
			pObj = (PooledObject) enumerate.nextElement();
			// 如果忙,等 5 秒
			if (pObj.isBusy()) {
				wait(5000); // 等 5 秒 
			}
			// 从对象池向量中删除它 
			objects.removeElement(pObj); 
		}
		// 置对象池为空 
		objects = null; 
	}
	/** 
	* 使程序等待给定的毫秒数 
	*/ 
	private void wait(int mSeconds) { 
		try { 
			Thread.sleep(mSeconds); 
		} catch (InterruptedException e) {
			
		} 
	}
	/** 
	* 内部使用的用于保存对象池中对象的类。
	* 此类中有两个成员,一个是对象,另一个是指示此对象是否正在使用的标志 。
	*/ 
	class PooledObject {
		Object objection = null;// 对象
		boolean busy = false; // 此对象是否正在使用的标志,默认没有正在使用
		// 构造函数,根据一个 Object 构告一个 PooledObject 对象
		public PooledObject(Object objection) {
			this.objection = objection;
		}
		// 返回此对象中的对象 
		public Object getObject() {
			return objection;
		}
		// 设置此对象的,对象
		public void setObject(Object objection) {
			this.objection = objection; 
		} 
		// 获得对象对象是否忙
		public boolean isBusy() {
			return busy;
		}
		// 设置对象的对象正在忙
		public void setBusy(boolean busy) {
			this.busy = busy; 
		}
	}
	
}

ObjectPoolTest.java 对象池测试用例代码如下:

代码语言:javascript
复制
package com.zhaoyanfei.designpattern.objectPoolPattern;


/**
 * 对象池测试类
 * @Date 2022年10月4日
 * @author zhaoYanFei
 *
 */
public class ObjectPoolTest {

	public static void main(String[] args) {
		//创建对象池
		ObjectPool objPool = new ObjectPool();
		objPool.createPool();
		//客户端请求对象池获取对象Object
		Object obj = objPool.getObject();
		/**
		 * TODO
		 * 此处拿到对象做一些具体的业务操作
		 */
		//对象用完后归还到对象池中,供其他客户端请求复用对象
		objPool.returnObject(obj);
		//最后这个操作是关闭对象池中所有对象,并清空对象池
		objPool.closeObjectPool();
	}
	
}

4、对象池模式的应用场景

对象池模式主要适用于以下应用场景。

(1)资源受限的场景。比如,不需要可伸缩性的环境(CPU\内存等物理资源有限),CPU性能不够强劲,内存比较紧张,垃圾收集,内存抖动会造成比较大的影响,需要提高内存管理效率, 响应性比吞吐量更为重要。

(2)在内存中数量受限的对象。

(3)创建成本高的对象,可以考虑池化。

补充:常见的使用对象池的场景有在使用Socket时的各种连接池、线程池、数据库连接池等。

 5、对象池模式的优缺点

5.1、优点

复用池中对象,消除创建对象、回收对象所产生的内存开销、CPU开销,以及跨网络产生的网络开销。

5.2、缺点

(1)增加了分配 / 释放对象的开销。

(2)在并发环境中,多个线程可能(同时)需要获取池中对象,进而需要在堆数据结构上进行同步或者因为锁竞争而产生阻塞,这种开销要比创建销毁对象的开销高数百倍。

(3)由于池中对象的数量有限,势必成为一个可伸缩性瓶颈。

(4)很难合理设定对象池的大小,如果太小,则起不到作用;如果过大,则占用内存资源过高。

 6、结语

对象池模式的整体设计思想就是:

当客户需要新资源时,会向资源池类申请,资源池类检查后获取第一个可用资源并将其返回给客户端。

客户端使用完资源后会进行资源释放,资源会重新回到资源池以便重复使用。

码字不易,看完之后,感觉对您还有些帮助的话,那就动动你发财的小手, 帮小编点个赞,顺便再帮小编点个免费的关注呀,我会持续为您更新设计模式相关的内容。

你的点赞就是对小编最大的支持与认可。

如果对博文有所疑问或者指正,还望评论区留言哦^_^。

今天就到这儿吧,下期我会逐步详细讲解设计模式中的行为型模式。

下期咱们不见不散……

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-10-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、对象池模式的定义
    • 1.1、先来看看百度百科的定义
      • 1.2、 对象池模式就是单例模式加享元模式
      • 2、为什么要用对象池模式
        • 2.1、原因
          • 2.2、解决方案
          • 3、对象池模式示例代码
          • 4、对象池模式的应用场景
          •  5、对象池模式的优缺点
            • 5.1、优点
              • 5.2、缺点
              •  6、结语
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档