MST

星途 面试题库

面试题:复杂业务场景下Java任务调度的设计与优化

假设在一个电商系统中,有多种任务需要调度执行,比如定时检查商品库存并补货、定时清理过期的订单、定时生成销售报表等。这些任务之间可能存在依赖关系,且部分任务执行时间较长。请设计一个完整的Java任务调度方案,涵盖调度框架选型、任务依赖处理、线程资源分配与优化等方面,并详细说明设计思路和关键代码实现。
46.2万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

调度框架选型

在Java中,有多种任务调度框架可供选择,如Quartz和Spring Task。考虑到电商系统任务的复杂性,包括任务依赖处理,Quartz是一个更合适的选择。Quartz是一个功能强大的开源任务调度框架,支持多种调度方式,并且可以方便地处理任务依赖。

任务依赖处理

  1. 定义任务依赖关系:可以使用有向无环图(DAG)来表示任务之间的依赖关系。每个任务是图中的一个节点,任务之间的依赖关系是图中的边。
  2. 拓扑排序:在调度任务之前,对任务依赖图进行拓扑排序,以确定任务的执行顺序。只有当一个任务的所有依赖任务都执行完成后,该任务才能被执行。

线程资源分配与优化

  1. 线程池:使用线程池来管理任务的执行线程。可以根据系统的硬件资源和任务的特性来设置线程池的大小。例如,如果任务执行时间较长,可以适当增加线程池的大小;如果任务执行时间较短且数量较多,可以适当减小线程池的大小。
  2. 动态调整:根据任务的执行情况和系统的负载动态调整线程池的大小。可以使用一些监控指标,如任务队列的长度、线程的利用率等,来决定是否需要增加或减少线程池中的线程数量。

设计思路

  1. 任务定义:定义每个具体的任务类,这些类实现Quartz的Job接口。在任务类中编写具体的业务逻辑,如检查商品库存并补货、清理过期订单、生成销售报表等。
  2. 依赖关系管理:构建任务依赖图,并通过拓扑排序确定任务执行顺序。
  3. 调度器配置:配置Quartz调度器,设置调度器的线程池大小等参数。
  4. 任务调度:根据拓扑排序后的任务顺序,将任务添加到调度器中,并设置任务的调度时间和触发条件。

关键代码实现

  1. 定义任务类
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

public class CheckStockJob implements Job {
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        // 检查商品库存并补货的业务逻辑
        System.out.println("Checking stock and replenishing...");
    }
}

public class CleanExpiredOrdersJob implements Job {
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        // 清理过期订单的业务逻辑
        System.out.println("Cleaning expired orders...");
    }
}

public class GenerateSalesReportJob implements Job {
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        // 生成销售报表的业务逻辑
        System.out.println("Generating sales report...");
    }
}
  1. 构建任务依赖图并进行拓扑排序
import java.util.*;

public class TaskDependencyGraph {
    private Map<String, List<String>> graph;

    public TaskDependencyGraph() {
        graph = new HashMap<>();
    }

    public void addDependency(String task, String dependency) {
        graph.putIfAbsent(task, new ArrayList<>());
        graph.get(task).add(dependency);
    }

    public List<String> topologicalSort() {
        Map<String, Integer> inDegree = new HashMap<>();
        for (String task : graph.keySet()) {
            inDegree.put(task, 0);
        }
        for (String task : graph.keySet()) {
            for (String dependency : graph.get(task)) {
                inDegree.put(dependency, inDegree.getOrDefault(dependency, 0) + 1);
            }
        }
        Queue<String> queue = new LinkedList<>();
        for (String task : inDegree.keySet()) {
            if (inDegree.get(task) == 0) {
                queue.add(task);
            }
        }
        List<String> result = new ArrayList<>();
        while (!queue.isEmpty()) {
            String task = queue.poll();
            result.add(task);
            if (graph.containsKey(task)) {
                for (String dependency : graph.get(task)) {
                    inDegree.put(dependency, inDegree.get(dependency) - 1);
                    if (inDegree.get(dependency) == 0) {
                        queue.add(dependency);
                    }
                }
            }
        }
        if (result.size() != graph.size()) {
            throw new RuntimeException("Graph contains a cycle");
        }
        return result;
    }
}
  1. 配置和启动Quartz调度器
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;

public class QuartzSchedulerExample {
    public static void main(String[] args) throws SchedulerException {
        SchedulerFactory schedulerFactory = new StdSchedulerFactory();
        Scheduler scheduler = schedulerFactory.getScheduler();

        TaskDependencyGraph graph = new TaskDependencyGraph();
        graph.addDependency("GenerateSalesReportJob", "CheckStockJob");
        graph.addDependency("GenerateSalesReportJob", "CleanExpiredOrdersJob");
        List<String> sortedTasks = graph.topologicalSort();

        for (String taskName : sortedTasks) {
            JobDetail jobDetail;
            if ("CheckStockJob".equals(taskName)) {
                jobDetail = JobBuilder.newJob(CheckStockJob.class)
                       .withIdentity("CheckStockJob", "group1")
                       .build();
            } else if ("CleanExpiredOrdersJob".equals(taskName)) {
                jobDetail = JobBuilder.newJob(CleanExpiredOrdersJob.class)
                       .withIdentity("CleanExpiredOrdersJob", "group1")
                       .build();
            } else {
                jobDetail = JobBuilder.newJob(GenerateSalesReportJob.class)
                       .withIdentity("GenerateSalesReportJob", "group1")
                       .build();
            }
            Trigger trigger = TriggerBuilder.newTrigger()
                   .withIdentity(taskName + "Trigger", "group1")
                   .startNow()
                   .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                           .withIntervalInSeconds(3600)
                           .repeatForever())
                   .build();
            scheduler.scheduleJob(jobDetail, trigger);
        }

        scheduler.start();
    }
}

以上代码实现了一个基于Quartz的电商系统任务调度方案,涵盖了任务依赖处理和线程资源管理等方面。通过这种方式,可以有效地调度和管理电商系统中的各种任务。