定时任务帮助类
package com.xcg.webapp.common;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 定时任务帮助类
 * final类不可以继承
 * */
public final class ScheduledThreadUtil {
    /**
     * 不可以创建新对象
     */
    private ScheduledThreadUtil() {
    }

    /**
     * 存储定时任务
     * */
    private static final Map<String, ScheduledFuture> scheduledFutureMap = new HashMap<>();

    /**
     * 可调度线程池
     * */
    private static ScheduledThreadPoolExecutor threadPoolExecutor = null;

    /**
     * 保持线程池单实例
     * */
    public static ScheduledThreadPoolExecutor getThreadPoolExecutorInstance() {
        if (threadPoolExecutor == null) {
            synchronized (ScheduledThreadUtil.class) {
                if (threadPoolExecutor == null) {
                    threadPoolExecutor = (ScheduledThreadPoolExecutor) Executors.newScheduledThreadPool(16);
                }
            }
        }
        return threadPoolExecutor;
    }

    /**
     * 执行定时任务
     * @param key          任务的唯一标识,用于避免重复添加相同任务。
     * @param job          需要执行的任务,实现了Runnable接口。
     * @param initialDelay 任务首次执行的延迟时间(秒)。
     * @param period       任务执行的周期时间(秒)。
     */
    public static void doJob(String key, Runnable job, long initialDelay, long period) {
        //避免重复的任务
        if (!scheduledFutureMap.containsKey(key)) {
            getThreadPoolExecutorInstance();
            // 参数1: task任务;
            // 参数2: 首次执行任务的延迟时间;
            // 参数3: 周期性执行的时间;
            // 参数4: 时间单位;
            ScheduledFuture<?> task = threadPoolExecutor.scheduleAtFixedRate(job, initialDelay, period, TimeUnit.SECONDS);
            scheduledFutureMap.put(key, task);
        }
    }

    /**
     * 执行定时任务(只执行一次)
     * @param key          任务的唯一标识,用于避免重复添加相同任务。
     * @param job          需要执行的任务,实现了Runnable接口。
     * @param initialDelay 任务首次执行的延迟时间(秒)。
     * */
    public static void doJobOnce(String key, Runnable job, long initialDelay) {
        //避免重复的任务
        if (!scheduledFutureMap.containsKey(key)) {
            getThreadPoolExecutorInstance();
            // 参数1: task任务;
            // 参数2: 首次执行任务的延迟时间;
            // 参数3: 时间单位;
            ScheduledFuture<?> task = threadPoolExecutor.schedule(job, initialDelay, TimeUnit.SECONDS);
            scheduledFutureMap.put(key, task);
        }
    }

    /**
     * 执行定时任务(指定执行次数)
     * @param key           任务的唯一标识,用于避免重复添加相同任务。
     * @param job           需要执行的任务,实现了Runnable接口。
     * @param initialDelay  任务首次执行的延迟时间(秒)。
     * @param period        任务执行的周期时间(秒)。
     * @param times         任务执行的次数。
     * @param taskConsuming 单次任务执行的大概耗时(秒数)。
     * */
    public static void doJobSomeTimes(String key, Runnable job, long initialDelay, long period, int times,long taskConsuming) {
        for (int k = 0; k < times; k++) {
            String idxKey = key + "_" + (k + 1);
            getThreadPoolExecutorInstance();
            // 参数1: task任务;
            // 参数2: 首次执行任务的延迟时间;
            // 参数3: 时间单位;
            if (k == 0) {
                ScheduledFuture<?> task = threadPoolExecutor.schedule(job, initialDelay, TimeUnit.SECONDS);
                scheduledFutureMap.put(idxKey, task);
            } else {
                //下一次执行任务需要延迟多少时间
                long nextJobDelay = initialDelay + ((period + taskConsuming) * k);
                ScheduledFuture<?> task = threadPoolExecutor.schedule(job, nextJobDelay, TimeUnit.SECONDS);
                scheduledFutureMap.put(idxKey, task);
            }
        }
    }

    /**
     * 停止定时任务(非强制,如果正在执行,会等待执行完成后再关闭。)
     */
    public static void removeJob(String key) {
        if (scheduledFutureMap.containsKey(key)) {
            ScheduledFuture<?> task = scheduledFutureMap.get(key);
            if (task != null) {
                task.cancel(false);
            }
            scheduledFutureMap.remove(key);
        }
    }

    /**
     * 停止定时任务(非强制,如果正在执行,会等待执行完成后再关闭。)
     */
    public static void removeTimesJob(String key, int times) {
        for (int k = 0; k < times; k++) {
            String idxKey = key + "_" + (k + 1);
            if (scheduledFutureMap.containsKey(idxKey)) {
                ScheduledFuture<?> task = scheduledFutureMap.get(idxKey);
                if (task != null) {
                    task.cancel(false);
                }
                scheduledFutureMap.remove(idxKey);
            }
        }
    }

    /**
     * 停止全部任务(非强制,如果正在执行,会等待执行完成后再关闭。)
     */
    public static void removeAllJob() {
        if (threadPoolExecutor != null) {
            threadPoolExecutor.shutdown();
        }
        scheduledFutureMap.clear();
    }

    /**
     * 是否已经存在job
     * */
    public static boolean existsJob(String key) {
        return scheduledFutureMap.containsKey(key);
    }
}

测试

        //设置定时任务
        ScheduledThreadUtil.doJob("job1", new Runnable() {
            @Override
            public void run() {
                System.out.println("定时任务1,每1秒执行一次:" + DateUtil.format(new Date(), DateUtil.DF_YYYY_MM_DDHHMMSS));
            }
        }, 1, 1);

        ScheduledThreadUtil.doJob("job2", new Runnable() {
            @Override
            public void run() {
                System.out.println("定时任务2,每5秒执行一次:" + DateUtil.format(new Date(), DateUtil.DF_YYYY_MM_DDHHMMSS));
            }
        }, 1, 5);

        Thread.sleep(20000);
        ScheduledThreadUtil.removeJob("job1");
        Thread.sleep(20000);
        ScheduledThreadUtil.removeAllJob();

 每天11点执行一次

        //任务周期,每天执行一次任务。
        long periodSec = TimeUnit.DAYS.toSeconds(1);
        //当前时间
        Date nowDate = new Date();
        //当前时间戳
        long nowTime = nowDate.getTime() / 1000L;
        //目标时间
        String ymd = DateUtil.format(nowDate, DateUtil.DF_YYYY_MM_DD);
        Date targetDate = DateUtil.parse(ymd + " 11:38:00", DateUtil.DF_YYYY_MM_DDHHMMSS);
        //如果当前时间大于11点,则目标时间为明天的11点。
        if (nowDate.after(targetDate)) {
            //加一天
            targetDate = DateUtil.add(targetDate, Calendar.DAY_OF_MONTH, 1);
        }
        long nowTime11 = targetDate.getTime() / 1000L;
        //首次延迟时间,单位为秒。
        long initialDelay = nowTime11 - nowTime;
        ScheduledThreadUtil.doJob("job3", new Runnable() {
            @Override
            public void run() {
                System.out.println("定时任务3,每天的11点执行一次:" + DateUtil.format(new Date(), DateUtil.DF_YYYY_MM_DDHHMMSS));
            }
        }, initialDelay, periodSec);

 

posted on 2023-08-10 09:24  邢帅杰  阅读(82)  评论(0)    收藏  举报