没有BUG就是最大的BUG 2022-07-18 14:15 采纳率: 66.7%
浏览 138
已结题

SpringBoot多线程并发动态执行定时任务可能出现的问题

请问我以下的代码会不会出现内存泄漏情况
@Component
public class ScheduledTask implements SchedulingConfigurer {
    private static volatile ScheduledTaskRegistrar registrar;
    private static volatile ConcurrentHashMap<Integer, ScheduledFuture<?>> scheduledFutures = new ConcurrentHashMap<Integer, ScheduledFuture<?>>();
    private static volatile ConcurrentHashMap<Integer, CronTask> cronTasks = new ConcurrentHashMap<Integer, CronTask>();

    @Override
    public void configureTasks(ScheduledTaskRegistrar registrar) {
        //设置20个线程,默认单线程
        registrar.setScheduler(Executors.newScheduledThreadPool(20));
        this.registrar = registrar;
    }

    public void refresh(List<LogTask> tasks) {
        //取消已经删除的策略任务
        Set<Integer> sids = scheduledFutures.keySet();
        for (Integer sid : sids) {
            if (!exists(tasks, sid)) {
                scheduledFutures.get(sid).cancel(false);
            }
        }

        for (LogTask logTask : tasks) {
            String expression = logTask.getExpression();
            //计划任务表达式为空则跳过
            if (StringUtils.isEmpty(expression)) {
                continue;
            }
            //计划任务已存在并且表达式未发生变化则跳过
            if (scheduledFutures.containsKey(logTask.getTask_id()) && cronTasks.get(logTask.getTask_id()).getExpression().equals(expression)) {
                continue;
            }
            //如果策略执行时间发生了变化,则取消当前策略的任务
            if (scheduledFutures.containsKey(logTask.getTask_id())) {
                scheduledFutures.get(logTask.getTask_id()).cancel(false);
                scheduledFutures.remove(logTask.getTask_id());
                cronTasks.remove(logTask.getTask_id());
            }
            CronTask task = new CronTask(new Runnable() {
                @Override
                public void run() {
                    //每个计划任务实际需要执行的具体业务逻辑
                    System.out.println("正在执行的任务ID: " + logTask.getTask_id() + " |执行的cron表达式: " + logTask.getExpression());
                }
            }, expression);
            ScheduledFuture<?> future = registrar.getScheduler().schedule(task.getRunnable(), task.getTrigger());
            cronTasks.put(logTask.getTask_id(), task);
            scheduledFutures.put(logTask.getTask_id(), future);
        }
    }

    private boolean exists(List<LogTask> tasks, Integer tid) {
        for (LogTask logTask : tasks) {
            if (logTask.getTask_id() == tid) {
                return true;
            }
        }
        return false;
    }

    @PreDestroy
    public void destroy() {
        registrar.destroy();
    }
}

  • 写回答

1条回答 默认 最新

  • Tomshidi 2022-07-18 14:37
    关注

    会出现内存泄漏。cronTasksscheduledFutures两个Map的key都是task_id,这个id是唯一的,也就意味着这两个Map的内容会无限增加,并且这两个Map是static静态,与类绑定无法被GC,那Map中的键值对自然也不会被GC,也就会残留大量已经执行完的无用Task与Future对象实例。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

问题事件

  • 系统已结题 7月26日
  • 已采纳回答 7月18日
  • 创建了问题 7月18日

悬赏问题

  • ¥15 微信公众号自制会员卡没有收款渠道啊
  • ¥15 stable diffusion
  • ¥100 Jenkins自动化部署—悬赏100元
  • ¥15 关于#python#的问题:求帮写python代码
  • ¥20 MATLAB画图图形出现上下震荡的线条
  • ¥15 关于#windows#的问题:怎么用WIN 11系统的电脑 克隆WIN NT3.51-4.0系统的硬盘
  • ¥15 perl MISA分析p3_in脚本出错
  • ¥15 k8s部署jupyterlab,jupyterlab保存不了文件
  • ¥15 ubuntu虚拟机打包apk错误
  • ¥199 rust编程架构设计的方案 有偿