状态机模式中的Task与对象池
Task
抽象带来Task
首先,假设我们有这么一段逻辑:收到一个参数,先校验格式是否正确,再提取相关的参数出来,执行我们的事务,然后构建结果并返回。伪代码如下:
/**
* 一个engine类
**/
public class Engine {
public void init();
public void cancel();
public void restart();
// 处理逻辑
public void handleEvent(Param param) {
validateParam(param);
retrieveParam(param);
handleTransaction(param);
buildResult(param);
response(param);
}
}
在上面的handleEvent方法里面,处理逻辑与Engine并没有太多的联系,我们可以将这个逻辑抽离出来,或者说可以变得更抽象一点,如下:
/**
* 一个engine类
**/
public class Engine {
public void init();
public void cancel();
public void restart();
// 将处理逻辑抽象成Task类之后,Engine变得很简洁了
public void handleEvent(Param param) {
new Task().start(param);
}
}
class Task{
public void start(Param param){
validateParam(param);
retrieveParam(param);
handleTransaction(param);
buildResult(param);
response(param);
}
}
当然,如果engine被调用非常频繁,那么每次处理都新建一个Task类的话,会容易浪费内存,可以再优化一下性能,如下:
/**
* 一个engine类
**/
public class Engine {
public void init();
public void cancel();
public void restart();
// 减少新对象的创建可以将Task对象变成单例模式,或者将方法变成静态,这里取后者
public void handleEvent(Param param) {
Task.start(param);
}
}
class Task{
public static void start(Param param){
// ......
}
}
异步需要状态
如果上面的处理步骤有一个很耗时,例如handleTransaction方法需要10s才能返回,那么我们就需要将这个方法改造成异步的了,要不然就很影响engine的吞吐效率。这样,我们就需要一个状态标识符,用来标识handleTransaction方法是否执行完成,这个标识符可以放在engine里面,engine创建一个Map<Param,boolean>的成员变量,当handleTransaction方法执行完成产生回调,engine继续执行剩下的方法。
/**
* 一个engine类
**/
public class Engine {
private Map<Param, Boolean> statusMap = new HashMap<Param, Boolean>();
public void init();
public void cancel();
public void restart();
/**
* 处理逻辑
**/
public void handleEvent(Param param) {
boolean isInitHandle = statusMap.getOrDefault(param, Boolean.FALSE);
if (isInitHandle) {
Task.handleParamBeforeTransaction(param);
Task.handleTransaction(param);
}else{
Task.buildResultAndResponse(param);
}
}
}
class Task{
public static void handleParamBeforeTransaction(Param param){
validateParam(param);
retrieveParam(param);
}
public static void handleTransaction(Param param){
}
public static void buildResultAndResponse(Param param) {
buildResult(param);
response(param);
}
}
不过,这样就破坏了Engine类的抽象,Engine是管理者,但是却持有每次请求的状态,这样的管理类管的太细。比较好的抽象方式是将赋予Task状态,Engine直接管理Task。
/**
* 一个engine类
**/
public class Engine {
private Map<Param, Task> taskMap = new HashMap<Param, Task>();
public void init();
public void cancel();
public void restart();
/**
* 处理逻辑
**/
public void handleEvent(Param param) {
Task task = taskMap.computeIfAbsent(param, newParam ->new Task());
task.handle(param);
}
public void releaseTask(Param param){
taskMap.remove(param);
}
}
class Task{
private boolean isInit ;
private Engine engine;
public Task(Engine engine) {
this.engine = engine;
isInit=false;
}
public void handle(Param param) {
if (!isInit) {
handleParamBeforeTransaction(param);
handleTransaction(param);
}else{
buildResultAndResponse(param);
engine.releaseTask(param);
}
}
private void handleParamBeforeTransaction(Param param){
validateParam(param);
retrieveParam(param);
}
private void handleTransaction(Param param){
}
private void buildResultAndResponse(Param param) {
buildResult(param);
response(param);
}
}
Task含有一个isInit的成员变量,可以根据这个状态来判断应该执行什么操作,实际上这就是状态机模式了。我们进行这般改造之后,Engine的吞吐量会提高很多,而且抽象程度比较高。
不过,每次处理Task都需要新建一个对象出来,又回到了刚开始的时候。一旦Engine的tps上去,不断创建、释放的Task对GC肯定有不小的影响。
对象池
不断创建的Task实例,如果整个处理逻辑的时间都比较短,那么都可以在YGC时回收掉内存,如果时间比较长,那肯定有相当部分的Task实例被不断地移到老年代,这样很显然会导致更长时间的FGC。异步要求保留状态,而有状态就要求有新实例,Task的创建不可避免,可以考虑将Task实例放到对象池里面回收利用。
/**
* 一个engine类
**/
public class Engine {
private Map<Param, Task> taskMap = new HashMap<Param, Task>();
public void init();
public void cancel();
public void restart();
/**
* 处理逻辑
**/
public void handleEvent(Param param) {
Task task = taskMap.computeIfAbsent(param, newParam -> TaskPool.getTask());
task.init(this);
task.handle(param);
}
public void releaseTask(Param param) {
Task task = taskMap.remove(param);
TaskPool.releaseTask(task);
}
}
/**
Task实例的对象池
*/
class TaskPool {
private static Queue<Task> taskPool = new LinkedList<>();
public static Task getTask() {
Task task = taskPool.poll();
if (task == null) {
task = new Task();
}
return task;
}
public static void releaseTask(Task task) {
if(task!=null) {
task.reset();
taskPool.add(task);
}
}
}
class Task {
private boolean isInit;
private Engine engine;
// 由于Task放到对象池当中,需要提供一个init与reset方法,以回收利用
public void init(Engine engine) {
this.engine = engine;
isInit = false;
}
public void reset() {
this.engine = null;
isInit = false;
}
public void handle(Param param) {
if (!isInit) {
handleParamBeforeTransaction(param);
handleTransaction(param);
} else {
buildResultAndResponse(param);
engine.releaseTask(param);
}
}
private void handleParamBeforeTransaction(Param param) {
validateParam(param);
retrieveParam(param);
}
private void handleTransaction(Param param) {
}
private void buildResultAndResponse(Param param) {
buildResult(param);
response(param);
}
}
由于Task实例从对象池(会放置到老年代里面)当中获取,这样就可以减少从新生代创建的内存浪费。这样在engine高tps的情况下,可以减少些gc,相当于从JVM的世界里面偷了点时间出来(这样想想还是有点刺激的)。
状态机模式中的Task与对象池的更多相关文章
- 在C#中实现简单的对象池
当我们频繁创建删除大量对象的时候,对象的创建删除所造成的开销就不容小觑了.为了提高性能,我们往往需要实现一个对象池作为Cache:使用对象时,它从池中提取.用完对象时,它放回池中.从而减少创建对象的开 ...
- GoLang设计模式06 - 对象池模式
这次介绍最后一个创建型模式--对象池模式.顾名思义,对象池模式就是预先初始化创建好多个对象,并将之保存在一个池子里.当需要的时候,客户端就可以从池子里申请一个对象使用,使用完以后再将之放回到池子里.池 ...
- 对象池模式(Object Pool Pattern)
本文节选自<设计模式就该这样学> 1 对象池模式的定义 对象池模式(Object Pool Pattern),是创建型设计模式的一种,将对象预先创建并初始化后放入对象池中,对象提供者就能利 ...
- Java 中的对象池实现
点赞再看,动力无限.Hello world : ) 微信搜「程序猿阿朗 」. 本文 Github.com/niumoo/JavaNotes 和 未读代码博客 已经收录,有很多知识点和系列文章. 最近在 ...
- 【JVM】Java 8 中的常量池、字符串池、包装类对象池
1 - 引言 2 - 常量池 2.1 你真的懂 Java的“字面量”和“常量”吗? 2.2 常量和静态/运行时常量池有什么关系?什么是常量池? 2.3 字节码下的常量池以及常量池的加载机制 2.4 是 ...
- java对象池commons-pool-1.6详解(一)
自己的项目中用到了 对象池 commons-pool: package com.sankuai.qcs.regulation.protocol.client; import com.dianping. ...
- 基于Apache组件,分析对象池原理
池塘里养:Object: 一.设计与原理 1.基础案例 首先看一个基于common-pool2对象池组件的应用案例,主要有工厂类.对象池.对象三个核心角色,以及池化对象的使用流程: import or ...
- common-pool2对象池(连接池)的介绍及使用
我们在服务器开发的过程中,往往会有一些对象,它的创建和初始化需要的时间比较长,比如数据库连接,网络IO,大数据对象等.在大量使用这些对象时,如果不采用一些技术优化,就会造成一些不可忽略的性能影响.一种 ...
- javascript设计模式学习之四——单例模式,缓存与对象池
单例模式的定义:确保一个实例,并提供全局访问. 惰性单例的定义:只在需要的时候才创建对象. 在开发中,有些对象往往只需要一个,比如线程池.全局缓存.浏览器中的window对象等. java中的单例 关 ...
随机推荐
- MySQL redo log及recover过程浅析
写在前面:作者水平有限,欢迎不吝赐教,一切以最新源码为准. InnoDB redo log 首先介绍下Innodb redo log是什么,为什么需要记录redo log,以及redo log的作用都 ...
- 好久没做.Net开发了,今天配置IIS和.Net Framework 4.0遇到点问题
装了64位的Win7后,装了VS再装IIS,结果IIS里面有.NET4.0,但是程序始终是跑不起来,最后觉得可能是因为4.0没有注册到IIS,因为之前在win2003中有遇到类似的情况.最终成功解决, ...
- KbmMW 4.40.00 正式版发布
经过快3个月的测试,kbmmw 4.40 正式版终于在圣诞节前发布了. We are happy to announce the availability of a new kbmMW release ...
- 团体程序设计天梯赛L1-020 帅到没朋友 2017-03-22 17:46 72人阅读 评论(0) 收藏
L1-020. 帅到没朋友 时间限制 200 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 陈越 当芸芸众生忙着在朋友圈中发照片的时候,总有一些人因为 ...
- B-spline Curves 学习之B样条曲线的移动控制点、修改节点分析(7)
B-spline Curves: Moving Control Points 本博客转自前人的博客的翻译版本,前几章节是原来博主的翻译内容,但是后续章节博主不在提供翻译,后续章节我在完成相关的翻译学习 ...
- Java Web系列:Spring MVC基础
1.Web MVC基础 MVC的本质是表现层模式,我们以视图模型为中心,将视图和控制器分离出来.就如同分层模式一样,我们以业务逻辑为中心,把表现层和数据访问层代码分离出来是一样的方法.框架只能在技术层 ...
- Web 协议 HTTP1.0 HTTP1.1 SPDY HTTP2.0
Web 协议 HTTP1.0 HTTP1.1 SPDY HTTP2.0 HTTP1.0 VS HTTP1.1 长连接HTTP 1.0需要使用keep-alive参数来告知服务器端要建立一个长连接,而H ...
- .net 开发者尝试Apache Spark™
本文编译自一篇msdn magazine的文章,原文标题和链接为: Test Run - Introduction to Spark for .NET Developers https://msdn. ...
- 基于Quartz.net的远程任务管理系统-起绪
Quartz.net这一个任务调度框架,相信大部分的开发者都非常的熟悉了. 往往在一个项目之中,我们会有很多的定时任务,加之多人参与编码,难免会有些难于管理等问题.为统一编写规范,以及对定时任务的管理 ...
- WPF 组织机构下拉树多选,递归绑定方式现实
使用HierarchicalDataTemplate递归绑定现实 XAML代码: <UserControl x:Class="SunCreate.CombatPlatform.Clie ...