首页 > 其他分享 >任务调度

任务调度

时间:2024-08-19 14:27:08浏览次数:11  
标签:10 15 任务 scheduler 定时 任务调度 public

java实现定时任务

定时任务种类:

  • Java自带的java.util.Timer类,这个类允许你调度一个java.util.TimerTask任务。使用这种方式可以让你的程序按照某一个频度执行,但不能在指定时间运行;而且作业类需要集成java.util.TimerTask,一般用的较少。

  • Spring3.0以后自带的task,即:spring schedule,可以将它看成一个轻量级的 Quartz ,而且使用起来比Quartz简单许多。

  • Quartz,这是一个功能比较强大的的调度器,可以让你的程序在指定时间执行,也可以按照某一个频度执行;代码稍显复杂。

  • xxl-job

https://blog.csdn.net/weixin_57109001/article/details/127301536?spm=1001.2014.3001.5502

一,jdk自带的Timer类

这是JDK自带的定时任务执行类,所以操作简单,使用方便,具体使用如下:

public class MyTime {
    public static void main(String[] args) {
        //自定义一个任务
        TimerTask task = new TimerTask() {
            @Override
            public void run() {
                //要执行的任务内容
                System.out.println("定时任务:" + new Date());
            }
        };
        Timer timer = new Timer();
        //延迟1S执行,每3S执行一次
        timer.schedule(task, 1000, 3000);
    }
}

执行内容如下:

定时任务:Thu Oct 13 14:53:41 CST 2022
定时任务:Thu Oct 13 14:53:44 CST 2022
定时任务:Thu Oct 13 14:53:47 CST 2022
定时任务:Thu Oct 13 14:53:50 CST 2022
定时任务:Thu Oct 13 14:53:53 CST 2022
定时任务:Thu Oct 13 14:53:56 CST 2022

  1. 由于执行任务的线程只有一个,所以如果某个任务的执行时间过长,那么将破坏其他任务的定时精确性。如一个任务每1秒执行一次,而另一个任务执行一次需要5秒,那么如果是固定速率的任务,那么会在5秒这个任务执行完成后连续执行5次,而固定延迟的任务将丢失4次执行。
  2. 如果执行某个任务过程中抛出了异常,那么执行线程将会终止,导致Timer中的其他任务也不能再执行。
  3. Timer使用的是绝对时间,即是某个时间点,所以它执行依赖系统的时间,如果系统时间修改了的话,将导致任务可能不会被执行。

由于Timer存在上面说的这些缺陷,在JDK1.5中,我们可以使用ScheduledThreadPoolExecutor来代替它,使用Executors.newScheduledThreadPool工厂方法或使用ScheduledThreadPoolExecutor的构造函数来创建定时任务,它是基于线程池的实现,不会存在Timer存在的上述问题,当线程数量为1时,它相当于Timer。

二,JDK1.5自带的ScheduledExecutorService

  public class SESTask {
    public static void main(String[] args) {
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(10);
        scheduledExecutorService.scheduleAtFixedRate(() -> {
        System.out.println("进入task" + new Date());
    }, 1, 3, TimeUnit.SECONDS);
}

}
执行结果如下:
进入taskThu Oct 13 14:59:10 CST 2022
进入taskThu Oct 13 14:59:13 CST 2022
进入taskThu Oct 13 14:59:16 CST 2022
进入taskThu Oct 13 14:59:19 CST 2022

三,Spring Task

Spring Task 底层是基于 JDK 的 ScheduledThreadPoolExecutor 线程池来实现的。

只需要两步即可实现:

1.开启定时任务只需要在 Spring Boot 的启动类上声明 @EnableScheduling 即可,实现代码如下:

@SpringBootApplication
@EnableScheduling // 开启定时任务
public class DemoApplication {

}

2.添加定时任务

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component // 把此类托管给 Spring,不能省略
public class TaskUtils {
    // 添加定时任务
    @Scheduled(cron = "59 59 23 0 0 5") // cron 表达式,每周五 23:59:59 执行
    public void doTask(){
        System.out.println("定时任务~");
    }
}

Cron表达式是一个字符串,字符串以5或6个空格隔开,分为6或7个域,每一个域代表一个含义,Cron有如下两种语法格式:
Seconds Minutes Hours DayofMonth Month DayofWeek Year或
Seconds Minutes Hours DayofMonth Month DayofWeek
每一个域可出现的字符如下:
Seconds:可出现", - * /"四个字符,有效范围为0-59的整数
Minutes:可出现", - * /"四个字符,有效范围为0-59的整数
Hours:可出现", - * /"四个字符,有效范围为0-23的整数
DayofMonth:可出现", - * / ? L W C"八个字符,有效范围为0-31的整数
Month:可出现", - * /"四个字符,有效范围为1-12的整数或JAN-DEc
DayofWeek:可出现", - * / ? L C #"八个字符,有效范围为1-7的整数或SUN-SAT两个范围。1表示星期天,2表示星期一, 依次类推
Year:可出现", - * /"四个字符,有效范围为1970-2099年
每一个域都使用数字,但还可以出现如下特殊字符,它们的含义是:
(1):表示匹配该域的任意值,假如在Minutes域使用, 即表示每分钟都会触发事件。
(2)?:只能用在DayofMonth和DayofWeek两个域。它也匹配域的任意值,但实际不会。因为DayofMonth和DayofWeek会相互影响。例如想在每月的20日触发调度,不管20日到底是星期几,则只能使用如下写法: 13 13 15 20 * ?, 其中最后一位只能用?,而不能使用,如果使用表示不管星期几都会触发,实际上并不是这样。
(3)-:表示范围,例如在Minutes域使用5-20,表示从5分到20分钟每分钟触发一次
(4)/:表示数值的增量,简单来说,比如分写上0/5表示从0分开始,每隔5分钟
(5),:表示列出枚举值值。例如:在Minutes域使用5,20,则意味着在第5和第20分钟分别触发一次。
(6)L:表示最后,只能出现在DayofWeek和DayofMonth域,如果在DayofWeek域使用5L,意味着在最后的一个星期四触发。
(7)W:表示有效工作日(周一到周五),只能出现在DayofMonth域,系统将在离指定日期的最近的有效工作日触发事件。例如:在 DayofMonth使用5W,如果5日是星期六,则将在最近的工作日:星期五,即4日触发。如果5日是星期天,则在6日(周一)触发;如果5日在星期一到星期五中的一天,则就在5日触发。另外一点,W的最近寻找不会跨过月份
(8)LW:这两个字符可以连用,表示在某个月最后一个工作日,即最后一个非周六周末的日期。
(9)#:用于确定每个月第几个星期几,只能出现在DayofWeek域。例如在4#2,表示某月的第二个星期三。
举几个例子:
0 0 2 1 * ? * 表示在每月的1日的凌晨2点调度任务
0 15 10 ? * MON-FRI 表示周一到周五每天上午10:15执行作业
0 15 10 ? * 6L 2002-2006 表示2002-2006年的每个月的最后一个星期五上午10:15执行作
0 0 10,14,16 * * ? 每天上午10点,下午2点,4点
0 0/30 9-17 * * ? 朝九晚五工作时间内每半小时
0 0 12 ? * WED 表示每个星期三中午12点
"0 0 12 * * ?" 每天中午12点触发
"0 15 10 ? * *" 每天上午10:15触发
"0 15 10 * * ?" 每天上午10:15触发
"0 15 10 * * ? *" 每天上午10:15触发
"0 15 10 * * ? 2005" 2005年的每天上午10:15触发
"0 * 14 * * ?" 在每天下午2点到下午2:59期间的每1分钟触发
"0 0/5 14 * * ?" 在每天下午2点到下午2:55期间的每5分钟触发
"0 0/5 14,18 * * ?" 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发
"0 0-5 14 * * ?" 在每天下午2点到下午2:05期间的每1分钟触发
"0 10,44 14 ? 3 WED" 每年三月的星期三的下午2:10和2:44触发
"0 15 10 ? * MON-FRI" 周一至周五的上午10:15触发
"0 15 10 15 * ?" 每月15日上午10:15触发
"0 15 10 L * ?" 每月最后一日的上午10:15触发
"0 15 10 ? * 6L" 每月的最后一个星期五上午10:15触发
"0 15 10 ? * 6L 2002-2005" 2002年至2005年的每月的最后一个星期五上午10:15触发
"0 15 10 ? * 6#3" 每月的第三个星期五上午10:15触发

四,Quartz

Quartz 主要是基于 Java 的任务调度框架,支持 Java 语言

https://blog.csdn.net/qq_32419139/article/details/131212271

https://cloud.tencent.com/developer/article/1640190

什么是Quartz?

一个定时任务调度框架,简单易用,功能强大可以使实现定时任务的。 在项目开发过程当中,某些定时任务,可能在运行一段时间之后,就不需要了,或者需要修改下定时任务的执行时间等等。 需要在代码当中进行修改然后重新打包发布,很麻烦。使用Quartz来实现的话不需要重新修改代码而达到要求。

springboot整合Quartz定时调度框架

开发环境

  1. JDK版本1.8
  2. springboot版本:2.1.0
  3. 开发工具:IDEA

实现一个简单的定时任务

第一步 引入对应的jar

在springboot2.0后官方添加了Quartz框架的依赖,所以只需要在pom文件当中引入

      <!--引入quartz定时框架-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-quartz</artifactId>
        </dependency>

第二步 创建一个定时任务

由于springboot2.0自动进行了依赖所以创建的定时任务类直接继承QuzrtzJobBean就可以了,新建一个定时任务类:MyTask

public class MyTask extends QuartzJobBean {
    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        //TODO 这里写定时任务的执行逻辑
        System.out.println("简单的定时任务执行时间:"+new Date().toLocaleString());
    }
}

第三步 创建Quartz配置类将之前创建的定时任务添加到定时调度里面

@Configuration
public class QuartzConfig {
	//指定具体的定时任务类
    @Bean
    public JobDetail uploadTaskDetail() {
        return JobBuilder.newJob(MyTask.class).withIdentity("MyTask").storeDurably().build();
    }

    @Bean
    public Trigger uploadTaskTrigger() {
        //TODO 这里设定执行方式
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule("*/5 * * * * ?");
        // 返回任务触发器
        return TriggerBuilder.newTrigger().forJob(uploadTaskDetail())
                .withIdentity("MyTask")
                .withSchedule(scheduleBuilder)
                .build();
    }
}

最后运行项目查看效果

成功执行任务

这种方式是写死在程序当中的,也存在修改不方便的情况!!!!!!

实现定时调度任务的动态暂停,修改,启动,单次执行等操作

第一步 创建一个定时任务相关实体类用于保存定时任务相关信息到数据库当中

public class QuartzBean {
    /** 任务id */
    private String  id;

    /** 任务名称 */
    private String jobName;

    /** 任务执行类 */
    private String jobClass;

    /** 任务状态 启动还是暂停*/
    private Integer status;

    /** 任务运行时间表达式 */
    private String cronExpression;
    //省略getter setter
  }

第二步 创建定时任务暂停,修改,启动,单次启动工具类

public class QuartzUtils {

    /**
     * 创建定时任务 定时任务创建之后默认启动状态
     * @param scheduler   调度器
     * @param quartzBean  定时任务信息类
     * @throws Exception
     */
    public static void createScheduleJob(Scheduler scheduler, QuartzBean quartzBean){
        try {
            //获取到定时任务的执行类  必须是类的绝对路径名称
            //定时任务类需要是job类的具体实现 QuartzJobBean是job的抽象类。
            Class<? extends Job> jobClass = (Class<? extends Job>) Class.forName(quartzBean.getJobClass());
            // 构建定时任务信息
            JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(quartzBean.getJobName()).build();
            // 设置定时任务执行方式
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(quartzBean.getCronExpression());
            // 构建触发器trigger
            CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(quartzBean.getJobName()).withSchedule(scheduleBuilder).build();
            scheduler.scheduleJob(jobDetail, trigger);
        } catch (ClassNotFoundException e) {
            System.out.println("定时任务类路径出错:请输入类的绝对路径");
        } catch (SchedulerException e) {
            System.out.println("创建定时任务出错:"+e.getMessage());
        }
    }

    /**
     * 根据任务名称暂停定时任务
     * @param scheduler  调度器
     * @param jobName    定时任务名称
     * @throws SchedulerException
     */
    public static void pauseScheduleJob(Scheduler scheduler, String jobName){
        JobKey jobKey = JobKey.jobKey(jobName);
        try {
            scheduler.pauseJob(jobKey);
        } catch (SchedulerException e) {
            System.out.println("暂停定时任务出错:"+e.getMessage());
        }
    }

    /**
     * 根据任务名称恢复定时任务
     * @param scheduler  调度器
     * @param jobName    定时任务名称
     * @throws SchedulerException
     */
    public static void resumeScheduleJob(Scheduler scheduler, String jobName) {
        JobKey jobKey = JobKey.jobKey(jobName);
        try {
            scheduler.resumeJob(jobKey);
        } catch (SchedulerException e) {
            System.out.println("启动定时任务出错:"+e.getMessage());
        }
    }

    /**
     * 根据任务名称立即运行一次定时任务
     * @param scheduler     调度器
     * @param jobName       定时任务名称
     * @throws SchedulerException
     */
    public static void runOnce(Scheduler scheduler, String jobName){
        JobKey jobKey = JobKey.jobKey(jobName);
        try {
            scheduler.triggerJob(jobKey);
        } catch (SchedulerException e) {
            System.out.println("运行定时任务出错:"+e.getMessage());
        }
    }

    /**
     * 更新定时任务
     * @param scheduler   调度器
     * @param quartzBean  定时任务信息类
     * @throws SchedulerException
     */
    public static void updateScheduleJob(Scheduler scheduler, QuartzBean quartzBean)  {
        try {
            //获取到对应任务的触发器
            TriggerKey triggerKey = TriggerKey.triggerKey(quartzBean.getJobName());
            //设置定时任务执行方式
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(quartzBean.getCronExpression());
            //重新构建任务的触发器trigger
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
            trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
            //重置对应的job
            scheduler.rescheduleJob(triggerKey, trigger);
        } catch (SchedulerException e) {
            System.out.println("更新定时任务出错:"+e.getMessage());
        }
    }

    /**
     * 根据定时任务名称从调度器当中删除定时任务
     * @param scheduler 调度器
     * @param jobName   定时任务名称
     * @throws SchedulerException
     */
    public static void deleteScheduleJob(Scheduler scheduler, String jobName) {
        JobKey jobKey = JobKey.jobKey(jobName);
        try {
            scheduler.deleteJob(jobKey);
        } catch (SchedulerException e) {
            System.out.println("删除定时任务出错:"+e.getMessage());
        }
    }
}

第三步 创建一个定时任务和相关测试类。

新建一个定时任务MyTask1

public class MyTask1 extends QuartzJobBean {

          //验证是否成功可以注入service   之前在ssm当中需要额外进行配置
//        @Autowired
//        private AccountService service;

        @Override
        protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
//            Account account = new Account();
//            account.setId(1);
//            account = service.findByAccount(account);
//            System.out.println(account.toString());
            //TODO 这里写定时任务的执行逻辑
            System.out.println("动态的定时任务执行时间:"+new Date().toLocaleString());
        }
}

新建一个测试Controller

@Controller
@RequestMapping("/quartz/")
public class QuartzController {
    //注入任务调度
    @Autowired
    private Scheduler scheduler;

    @RequestMapping("/createJob")
    @ResponseBody
    public String  createJob(QuartzBean quartzBean)  {
        try {
            //进行测试所以写死
            quartzBean.setJobClass("com.hjljy.blog.Quartz.MyTask1");
            quartzBean.setJobName("test1");
            quartzBean.setCronExpression("*/10 * * * * ?");
            QuartzUtils.createScheduleJob(scheduler,quartzBean);
        } catch (Exception e) {
            return "创建失败";
        }
        return "创建成功";
    }

    @RequestMapping("/pauseJob")
    @ResponseBody
    public String  pauseJob()  {
        try {
            QuartzUtils.pauseScheduleJob (scheduler,"test1");
        } catch (Exception e) {
            return "暂停失败";
        }
        return "暂停成功";
    }

    @RequestMapping("/runOnce")
    @ResponseBody
    public String  runOnce()  {
        try {
            QuartzUtils.runOnce (scheduler,"test1");
        } catch (Exception e) {
            return "运行一次失败";
        }
        return "运行一次成功";
    }

    @RequestMapping("/resume")
    @ResponseBody
    public String  resume()  {
        try {

            QuartzUtils.resumeScheduleJob(scheduler,"test1");
        } catch (Exception e) {
            return "启动失败";
        }
        return "启动成功";
    }

    @RequestMapping("/update")
    @ResponseBody
    public String  update(QuartzBean quartzBean)  {
        try {
            //进行测试所以写死
            quartzBean.setJobClass("com.hjljy.blog.Quartz.MyTask1");
            quartzBean.setJobName("test1");
            quartzBean.setCronExpression("10 * * * * ?");
            QuartzUtils.updateScheduleJob(scheduler,quartzBean);
        } catch (Exception e) {
            return "启动失败";
        }
        return "启动成功";
    }
}

然后在网页上输入对应URL进行暂停,启动,创建,修改,单次运行等操作就可以了。

第四步 总结

1 springboot2.0后默认添加了quartz的依赖,可以少些很多配置信息,只需要写好自己的任务类(需要实现job类)然后通过调度器scheduler添加任务就可以了。

2 通过@Bean注解简单创建定时任务的时候,直接写任务类的class就可以,但是通过scheduler的时候需要写绝对名称。

3 在quartz任务暂停之后再次启动时,会立即执行一次,在更新之后也会立即执行一次。

4 在springboot当中默认quartz线程池大小为10。

5 在启动项目初始化时需要将项目的定时任务也进行初始化。这样比较方便不用依次进行启动

五,xxl-job

https://blog.csdn.net/qq_16855077/article/details/111047768?utm_medium=distribute.wap_relevant.none-task-blog-2defaultbaidujs_baidulandingword~default-0-111047768-blog-80864406.237%5Ev3%5Ewap_relevant_t0_download&spm=1001.2101.3001.4242.1

万字长文简单明了的介绍xxl-job以及quartz

https://zhuanlan.zhihu.com/p/341363916?utm_id=0

XXL-Job 和 Quartz 区别

XXL-Job 和 Quartz 都是 Java 项目中常用的定时任务框架,它们有以下几点区别:

xxl-job 和 Quartz 都是用于任务调度的开源框架,它们之间有一些区别,主要体现在以下几个方面:

语言支持:

Quartz 主要是基于 Java 的任务调度框架,支持 Java 语言。
xxl-job 是一个分布式任务调度平台,它提供了 Java 版本的调度中心,同时还提供了 Python、PHP 等语言的任务执行器,因此支持多种语言。
分布式支持:

Quartz 本身并不提供原生的分布式支持,需要通过一些扩展或者和其他组件结合来实现分布式任务调度。
xxl-job 专注于分布式任务调度,提供了分布式任务调度的解决方案,可以在多个节点上进行任务调度和执行。
管理界面和监控功能:

Quartz 并没有提供官方的任务调度管理界面和监控功能,通常需要结合其他组件或者自行开发管理界面。
xxl-job 提供了任务调度中心,包括任务管理、调度监控、日志查看等功能,方便管理和监控任务的执行情况。
社区活跃度:

Quartz 是一个非常成熟和稳定的任务调度框架,拥有庞大的用户社区和丰富的生态系统。
xxl-job 相对较新,但也有着活跃的社区和持续的更新支持。
总的来说,Quartz 是一个强大的、成熟的任务调度框架,主要支持 Java 语言,而 xxl-job 则是一个专注于分布式任务调度的平台,支持多种语言,并提供了任务调度中心和监控功能。选择使用哪个框架取决于具体的需求和场景。

标签:10,15,任务,scheduler,定时,任务调度,public
From: https://www.cnblogs.com/pyb999/p/18367217

相关文章

  • 利用Quartz实现复杂的任务调度
    原文地址:java-利用Quartz实现复杂的任务调度-宋小黑-SegmentFault思否  第一章:引言大家好,我是小黑,任务调度,简而言之,就是按照预定计划自动执行任务的过程。不管是数据库备份、报表生成还是发送定时邮件,它们都需要一个可靠的任务调度系统来保证按时完成。那么,为什么......
  • FreeRTOS学习:任务调度
     注:在使用大多数功能时,FreeRTOS都要将对应的宏置为1,具体的需要查看FreeRTOS官方文档。 任务堆栈相关寄存器如下,启动第一个任务FreeRTOS中启动第一个任务的流程总结如下,启动任务调度器vTaskStartScheduler()在该函数中会创建空闲任务prvIdleTask和软件定时器任务xTimerC......
  • .NET 轻量化定时任务调度 FreeScheduler
    前言在平时项目开发中,定时任务调度是一项重要的功能,广泛应用于后台作业、计划任务和自动化脚本等模块。FreeScheduler是一款轻量级且功能强大的定时任务调度库,它支持临时的延时任务和重复循环任务(可持久化),能够按秒、每天/每周/每月固定时间或自定义间隔执行(CRON表达式)。此外......
  • Spring Cloud Alibaba 集成分布式定时任务调度功能
    作者:千习背景简介定时任务是指在约定的时间,或者按照固定频率周期性执行的任务。在企业应用中,非用户行为发起的后台业务,一般都是通过定时任务来实现,常见场景如下:异步数据处理:比如先将订单入库,每分钟扫描未支付的订单做批处理。自动化运维:比如每小时清理一次数据库的历史记录。......
  • 分布式任务调度的架构与选型
    场景任务调度是指系统在约定的特定时刻自动去执行指定任务的过程。比如:某新闻App每天上午10点给用户推送最新新闻。某电商系统需要在每天上午10点,下午3点,晚上8点等不同适合发放一批优惠券。某银行系统需要在信用卡到期还款日的前三天每天进行短信提醒。某财务系统需要......
  • FreeRTOS启动任务调度器函数解释
    目录vTaskStartScheduler()函数xPortStartScheduler()函数prvStartFirstTask()函数vPortSVCHandler()函数FreeRTOS的任务开始运行的前提是调用了启动调度器函数vTaskStartScheduler(),只有调用了该函数任务才会被调度并运行。下面以FreeRTOSv9.0.0版本的源码进行分析FreeRT......
  • 前端实现【 批量任务调度管理器 】demo优化
    一、前提介绍我在前文实现过一个【批量任务调度管理器】的demo,能实现简单的任务批量并发分组,过滤等操作。但是还有很多优化空间,所以查找一些优化的库,主要想优化两个方面,上篇提到的:针对3,其实可以自己手写一个,也可以依靠如什么来实现。针对2,最难的是根据【当前系统负......
  • Java中的定时任务调度:Quartz详解
    Java中的定时任务调度:Quartz详解大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!在现代软件开发中,定时任务调度是一项非常常见的需求。Quartz是Java平台上一个强大且灵活的任务调度库,广泛应用于企业级应用中。本文将深入探讨Quartz的基本概念、配置方法和......
  • Java中的分布式任务调度与Quartz框架应用
    Java中的分布式任务调度与Quartz框架应用大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!在现代软件开发中,分布式系统的任务调度变得越来越重要。本文将深入探讨如何利用Java中的Quartz框架来实现分布式任务调度,以及在实际应用中的一些最佳实践和设计考虑......
  • 基于 SSH 的任务调度系统的设计与实现
    点击下载源码基于SSH的任务调度系统的设计与实现摘要随着科学技术的飞速发展和各行各业的分工愈发明细化,对于改革传统的人工任务调度方式的呼声越来越大。得益于快速发展的计算机技术,我们看到了改革的方向。本系统是针对企业或者事业单位甚至一个小团队的任务调度而设计......