有依赖的并发任务执行-代码实践(工厂、模板模式、线程池的使用)-原型篇

 

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并发编程实战》

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值