(代码可直接复用)springboot框架下使用ThreadPoolTaskScheduler搭建动态定时任务增删改查,实现任务的延时控制、平滑切换;工厂模式选择不同任务实现对象

因项目上有动态任务的需求,因此写了一个demo
项目需求:
1、多任务执行,可增删改查(不同任务使用工厂模型)
2、任务执行时间可延时控制
3、任务平滑切换(同一模型任务,如有当前任务,定时任务执行前,当前任务需继续执行)
线程池选择:ThreadPoolTaskScheduler
ThreadPoolTaskScheduler是spring框架根据java内置的定时任务线程池ScheduledExecutorService,封装的一个适用于spring框架的线程池工具类,它比ScheduledExecutorService最大的优势是,支持cron表达式(因为我们这边需要设置任务开始时间,没有使用cron表达式)
效果1:多任务并行动态运行
下图为接口入参,模型编号为test1和test2,任务类型为当前任务,任务周期为5000毫秒
在这里插入图片描述
在这里插入图片描述
结果:两个任务同时运行
在这里插入图片描述
效果2:任务平滑切换
现在(19:00)将test1任务周期改为8000毫秒,rwlx为定时任务
在这里插入图片描述
结果:在定时任务开始之前,当前任务正常运行,到了定时时间,平滑切换
在这里插入图片描述
实现步骤:
具体逻辑可看代码内注解,比较详细
首先依次创建以下几个类
1、控制层类

@RestController
@RequestMapping("/modelService/v1")
public class ModelController {

    @Autowired
    private ModelService modelService;

    @RequestMapping(value = "/analyseModels.do", method = {RequestMethod.POST})
    public String Analysis(@RequestBody RequestParam requestParam){
        try {
            modelService.analysis(requestParam.getMxbh(),requestParam.getSfqy(),requestParam.getMxkssj(),requestParam.getRwlx(),requestParam.getCron());
        } catch (Exception e) {
            return e.getMessage();
        }
        return "成功";
    }
}

2、实现层类

@Service
public interface ModelService {
    void analysis(String mxbh, String sfqy, Date mxkssj, Integer rwlx, long cron);
}
@Service
public class ModelServiceImpl implements ModelService {

    @Autowired
    private Analysiser analysiser;

    @Override
    public void analysis(String mxbh, String sfqy, Date mxkssj, Integer rwlx, long cron) {
        //任务类型为0时,为当前任务;否则为定时任务
        if(rwlx==0)
            analysiser.currentTaskAnalysis(mxbh, sfqy,mxkssj,cron, getTask(mxbh));
        else
            analysiser.cronTaskAnalsis(mxbh, sfqy,mxkssj,cron, getTask(mxbh));
    }

    private Class<? extends CompareTask> getTask(String mxbh) {
        switch (mxbh) {
            case "test1": {
                return TestCompareTask.class;
            }
            case "test2":{
                return TestCompareTask2.class;
            }
        }
        return null;
    }
}

3、任务实现类

@Service
@Slf4j
public class Analysiser {

    @Autowired
    private ThreadPoolTaskScheduler threadPoolTaskScheduler;

    @Autowired
    private TestCompareTask testCompareTask;

    // 定时任务管理器(用于存储正在执行中的任务) ConcurrentHashMap保证线程安全
    public static ConcurrentHashMap<String, ScheduledFuture> currentTaskemap = new ConcurrentHashMap<String, ScheduledFuture>();
    private ScheduledFuture<?> future;
    //private  String cron = "0/1 * * * * ?";


    //该方法用于增加、修改、取消当前任务
    public <T> void  currentTaskAnalysis(String mxbh, String sfqy, Date mxkssj, long cron, Class<T> task)  {
        //mxbh可以唯一确定一个任务;sfqy表示任务停止或启动;mxkssj表示任务开始的时间;cron表示定时周期,task表示定时任务
        //判断任务管理器里是否已存在该任务且需要启用任务,如果存在则先停止;否则直接启动新任务。(sqy字段:0为启用,1为停止)
        if(!StringUtils.isEmpty(sfqy)&&sfqy.equals("0")){
            if(currentTaskemap.containsKey(mxbh)){
                ScheduledFuture scheduledFuture = currentTaskemap.get(mxbh);
                scheduledFuture.cancel(true);
                currentTaskemap.remove(mxbh);
            }
            try {
                future = threadPoolTaskScheduler.scheduleAtFixedRate(()->{
                    String string ="";
                    try {
                        CompareTask compareTask = (CompareTask)task.newInstance();
                        string = compareTask.getCompareTask(mxbh);
                    } catch (Exception e) {
                       log.error("-1",e );
                    }

                        log.debug("定时任务"+string+"开启成功,运行周期为:"+cron+"毫秒");

                }, mxkssj,cron);
                currentTaskemap.put(mxbh, future);
                System.out.println(currentTaskemap.toString());
            } catch (Exception e) {
                log.error("-1",e );
            }
        }else if(!StringUtils.isEmpty(sfqy)&&sfqy.equals("1")&&currentTaskemap.containsKey(mxbh)){
            if (true) {
                currentTaskemap.get(mxbh).cancel(true);
                currentTaskemap.remove(mxbh);
                System.out.println(currentTaskemap);
            }
            log.debug("定时任务关闭");
        }
    }

    //该方法用于同一模型,有定时任务时,平滑切换任务
    public void cronTaskAnalsis(String mxbh, String sfqy, Date mxkssj, long cron, Class<? extends CompareTask> task) {
        //创建线程任务,在mxkssj前当前任务继续执行,到了mxkssj时间,当前任务停止,执行定时任务
        if(!StringUtils.isEmpty(sfqy)&&sfqy.equals("0")){
            /*到达指定时间mxkssj,切换任务*/
            ScheduledFuture<?> schedule = threadPoolTaskScheduler.schedule( ()->{
                if (currentTaskemap.containsKey(mxbh)) {//判断任务池里已有该部门的模型时,需先将之前的任务取消
                    currentTaskemap.get(mxbh).cancel(true);//获取任务future并取消
                    currentTaskemap.remove(mxbh);//移除任务
                }
                currentTaskAnalysis(mxbh, sfqy,mxkssj,cron, task);
                log.debug("定时任务开启成功");
            },mxkssj);
        }
    }
}

4、线程池配置类

@Configuration
@Slf4j
public class ThreadPoolConfig {

    @Bean(name = "threadPoolTaskScheduler")
    public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
        ThreadPoolTaskScheduler executor = new ThreadPoolTaskScheduler();
        executor.setPoolSize(60);
        executor.setRemoveOnCancelPolicy(true);
     	executor.setThreadNamePrefix("analyseTaskExecutor-");
        //executor.setAwaitTerminationSeconds(60);
        return executor;
    }
}

5、参数类

@Data
public class RequestParam {
    private String mxbh;//模型编号
    private String sfqy;//是否启用
    private String sffx;
    private Integer rwlx;//0为修改当前任务,1为新建定时任务
    private long cron;//定时周期
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
    private Date mxkssj;//模型分析开始时间
}

使用工厂模式,根据mxbh选择不同类型的模型实现
工厂模式选择不同类型模型
根据上图getTask()方法内传入不同mxbh,实现不同模型的对象

    private Class<? extends CompareTask> getTask(String mxbh) {
        switch (mxbh) {
            case "test1": {
                return TestCompareTask.class;
            }
            case "test2":{
                return TestCompareTask2.class;
            }
        }
        return null;
    }

6、模型实现类

public  interface CompareTask{
     String getCompareTask(String mxbh);
}
@Component
public class TestCompareTask implements CompareTask {

    @Override
    public String getCompareTask(String mxbh) {
        //根据模型规则做处理
        System.out.println("test1任务执行成功");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "test1";
    }
}
@Component
public class TestCompareTask2 implements CompareTask {
    @Override
    public String getCompareTask(String bmbh) {

            System.out.println("test2任务执行成功");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "test2";
    }
}

多有不足,欢迎各位大佬,一起交流学习

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值