1、背景
一组任务并发执行,如任务A、B、C、D,其中有状态依赖关系,如D依赖C,即C任务执行完毕后,D任务才能开始执行。
2、实现思路
2.1、接口定义
(1) 任务执行(业务处理相关接口)( IDataHolder)
(2) 任务依赖接口(IDependTask)
(3) 任务状态管理接口(是否完成等)( ITaskMgr)
(4) 缓存清理接口(IReleaseCache)
以上接口设计,接口各司其能,耦合性降低,简单明确,易于扩展。其中IDataHolder提供AbstractDataHolder抽象类实现,其中定义模板方法(定义为final),固定业务处理行为。
2.2、工厂生成实例
定义DataHolderFactory生成不同类型的IDataHolder实例
2.3、任务执行管理类
TaskMgr负责整体调度所有的任务,接收输入为需要处理的IDataHolder集合。
2.4、对外提供服务类
DataService负责对外提供数据处理服务,接收参数场景上下文,内部调用工厂类生成具体IDataHolder实例,调起TaskMgr中调度任务接口。
设计特点:
1、简洁、分工明确、结构清晰
2、耦合性低
3、扩展性强
缺陷:
1、依赖关系耦合于各DataHolder的实现类中,最好抽象到任务层面或者由任务调度框架统一管理
2、任务全部一并提交到线程池中,部分任务只能等待依赖任务执行完毕才能继续进行,期间只能自旋等待,造成线程及CPU资源浪费。
3、代码实现
接口:
public interface IDataHolder extends IReleaseCache, ITaskMgr, IDependTask<IDataHolder>
{
/**
* getOriginalDatas 获取源数据<br>
*/
public Map<EnumStep, Object> getOriginalDatas();
/**
* 设置原始数据<br>
*/
public void setOriginalData(EnumStep step, Object object);
/**
* 生成数据及结果统计信息<br>
*/
public void diffAndStats();
/**
*数据、Summary持久化<br>
*/
public void persist();
/**
* processData<br>
* 进行数据处理,并把结果入库<br>
*/
public void processData ();
}
/**
* IDependTask<br>
*/
public interface IDependTask<T>
{
/**
* getDependTasks
* 获取依赖的任务列表
*/
public List<T> getDependTasks();
}
public interface IReleaseCache
{
/**
* releaseCacheInMemory<br>
* 释放内存中的缓存<br>
*/
void releaseCacheInMemory();
/**
* clearDataInDb<br>
* 清除数据库中的数据<br>
*/
void clearDataInDb();
}
public interface ITaskMgr
{
/**
* isFinish<br>
*任务是否完成
*/
boolean isTaskFinish();
/**
* setTaskFinish<br>
*/
void setTaskFinish();
}
抽象类实现模板方法:
(具体实现类-略)
public abstract class AbstractDataHolder<T> implements IDataHolder
{
private static final Logger LOGGER = xxx;
protected Object originalDataBefore;
protected Object originalDataAfter;
private volatile boolean isTaskFinish = false;
private List<IDataHolder> dependTasks = new LinkedList<>();
/**
* 结果数据
*/
@Getter
@Setter
private List<T> dataResult = new ArrayList<T>();
/*
* 统计信息缓存
*/
@Getter
@Setter
private BaseSummary summary;
public AbstractDataHolder(IDataHolder... dataTasks)
{
if (dataTasks != null)
{
for (IDataHolder dataTask : dataTasks)
{
this.dependTasks.add(dataTask);
}
}
}
@Override
public final void processData ()
{
// 1、清除上次生成的数据
this.clearDataInDb();
// 2、获取前后的源数据
Map<EnumStep, Object> originalDatas = this.getOriginalDatas();
// 3、设置源数据到originalDataBefore和originalDataAfter中
Object originalDataBefore = originalDatas.get(EnumStep.BEFORE);
Object originalDataAfter = originalDatas.get(EnumStep.AFTER);
if (null == originalDataBefore || null == originalDataAfter)
{
LOGGER.error("Invalid data, original data(before or after) is empty");
this.setTaskFinish();
return;
}
this.setOriginalData(EnumStep.BEFORE, originalDataBefore);
this.setOriginalData(EnumStep.AFTER, originalDataAfter);
// 4、数据对比,产生对比差异数据和统计数据Summary data
this.diffAndStats();
// 5、结果入库,差异数据、统计数据入库
this.persist();
// 6、设置当前diff任务为完成
this.setTaskFinish();
// 7、释放缓存加快GC
releaseCacheInMemory();
}
@Override
public final List<IDataHolder> getDependTasks()
{
return this.dependHolderTasks;
}
@Override
public final void releaseCacheInMemory()
{
originalDataBefore = null;
originalDataAfter = null;
resultData = null;
summary = null;
}
@Override
public final boolean isTaskFinish()
{
return this.isTaskFinish;
}
@Override
public final void setTaskFinish()
{
this.isTaskFinish = true;
}
@Override
public abstract void setOriginalData(EnumStep step, Object object);
@Override
public abstract Map<EnumStep, Object> getOriginalDatas();
@Override
public abstract void diffAndStats();
@Override
public abstract void persist();
@Override
public abstract void clearDataInDb();
}
工厂类:
public class DataHolderFactory
{
/**
* createDataHolder <br>
*
* @param type 类型
* @param dataHolders 依赖的dataHolder
* @return IDataHolder
*/
public static IDataHolder createDataHolder(EnumBusinessType type, IDataHolder... dataHolders)
{
if (type == EnumBusinessType.xxx)
{
return new XXXDataHolder(dataHolders);
}
else if (type == EnumBusinessType.xxx)
{
return new XXXDataHolder(dataHolders);
}
else if (type == EnumBusinessType.xxx)
{
return new XXXDataHolder(dataHolders);
}
else if (type == EnumBusinessType. xxx)
{
return new XXXDataHolder (dataHolders);
}
return null;
}
任务执行类:
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* TaskMgr<br>
* 数据任务管理类<br>
*/
public class TaskMgr
{
private static final Logger LOGGER = xxx;
/**
* process<br>
* @param dataHolders 要进行数据对比的任务
*/
public static void diff(Map<EnumBusinessType, IDataHolder> dataHolders)
{
LOGGER.info("tasks start");
// 1、任务并发数量
int taskSize = dataHolders.size();
if (taskSize <= 0)
{
LOGGER.error("Invalid param for diff tasks start");
return;
}
// 2、创建线程池 多线程执行
ExecutorService executor = Executors.newFixedThreadPool(taskSize);
// 3、创建多线程任务执行器
CompletionService<Boolean> completionService = new ExecutorCompletionService<Boolean>(
executor);
// 4、提交任务
for (Entry<EnumBusinessType, IDataHolder> entry : dataHolders.entrySet())
{
final EnumBusinessType type = entry.getKey();
final IDataHolder dataHolder = entry.getValue();
completionService.submit(new Callable<Boolean>()
{
@Override
public Boolean call() throws Exception
{
// 执行任务
return runTask(type, dataHolder);
}
});
}
// 4、待所有任务获取结果数据-是否成功
List<Boolean> taskStatus = new ArrayList<>();
try
{
for (int taskCount = 0; taskCount < taskSize; taskCount++)
{
taskStatus.add(completionService.take().get());
}
}
catch (InterruptedException | ExecutionException e)
{
LOGGER.error(e,
" Task InterruptedException | ExecutionException.");
}
catch (Exception e)
{
LOGGER.error(e, " Task exception.");
}
finally
{
// 5、关闭线程池
try
{
executor.shutdownNow();
executor.awaitTermination(Const.TIMEOUT, Const.TIME_UNIT_SECONDS);
}
catch (InterruptedException e)
{
LOGGER.error(e, "Executor service shut down fail, Exception is: ");
}
}
LOGGER.info("All tasks end, result is " + taskStatus.toString());
}
// 启动任务,循环判断是否能执行,阻塞线程
private static boolean runTask(EnumBusinessType type, IDataHolder dataHolder)
{
LOGGER.info(" Task start, type is " + type);
// 1、循环调起任务
while (true)
{
// 2、尝试启动数据任务
boolean isFinish = process(dataHolder);
// 3、任务完成后,跳出循环
if (isFinish)
{
break;
}
// 4、轮询间隔1s
try
{
Const.TIME_UNIT_SECONDS.sleep(1);
}
catch (InterruptedException e)
{
LOGGER.error(e, "Task interrupted exception.");
}
}
LOGGER.info(" Task end, type is " + type);
// 5、任务结束返回
return true;
}
/**
* process<br>
* 处理数据对比任务, 完成后返回true, 其他返回false<br>
*
* @param dataHolder 任务实例
* @return 对比任务是否处理完毕
*/
private static boolean process(IDataHolder dataHolder)
{
// 1、初始化当前任务状态为可执行
boolean canStart = true;
// 2、遍历依赖的任务是否已经完成,存在依赖的任务未完成,置当前任务不可执行
for (IDataHolder holderTask : dataHolder.getDependTasks())
{
if (!holderTask.isTaskFinish())
{
LOGGER.info(String.format("Depend tasks have not finished, wait... current task is %s, wait task is %s", dataHolder, holderTask));
canStart = false;
break;
}
}
// 3、任务可执行,则开始数据对比任务,完成后返回true
if (canStart)
{
dataHolder.processData();
return true;
}
// 4、任务不可执行,返回false
return false;
}
}
}
对外提供服务类:
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.springframework.stereotype.Service;
import com.google.common.collect.ImmutableList;
@Service
public class DiffService
{
private static final Logger LOGGER = xx;
/**
* 没有依赖项的任务类型
*/
private static final List<EnumBusinessType> BUSINESS_TYPES_NO_DEPEND = ImmutableList
.of(EnumBusinessType.xxx, EnumBusinessType.xx,
EnumBusinessType.xx);
/**
* 有依赖的任务缓存 依赖->被依赖
*/
private static final Map<EnumBusinessType,EnumBusinessType> BUSINESS_TYPES_DEPEND = new HashMap<>();
static
{
BUSINESS_TYPES_DEPEND.put(EnumBusinessType.xxx, EnumBusinessType.xxx);
}
public void processData ()
{
// 1、准备工作
doPre();
// 2、触发任务
DiffTaskMgr.diff(createDataHolders());
// 3、后续处理工作
doPost();
}
private Map<EnumBusinessType, IDataHolder> createDataHolders()
{
Map<EnumBusinessType, IDataHolder> dataHolders = new HashMap<EnumBusinessType, IDataHolder>();
// 1、添加没有依赖的Diff任务到Map中
for (EnumBusinessType type : BUSINESS_TYPES_NO_DEPEND)
{
dataHolders.put(type, DiffDataHolderFactory.createDataHolder(type));
}
// 2、添加有依赖的任务到Map中
for (Entry<EnumBusinessType, EnumBusinessType> entry : BUSINESS_TYPES_DEPEND
.entrySet())
{
// 2.1、获取被依赖的任务实例
EnumBusinessType depend = entry.getValue();
IDataHolder dependInstance = dataHolders.get(depend);
// 2.2、添加依赖的实例到Map中
EnumBusinessType key = entry.getKey();
dataHolders.put(key, DataHolderFactory.createDataHolder(key, dependInstance));
}
return dataHolders;
}
private void doPre()
{
// 1、设置场景上下文
// 2、清除上次缓存数据
}
private void doPost()
{
// 清理缓存等
}
}
优化篇:
有依赖的并发任务执行-代码实践(工厂、模板模式、线程池的使用)-优化篇
参考:
《Java并发编程实战》