最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring動態(tài)管理定時任務(wù)之ThreadPoolTaskScheduler解讀

 更新時間:2022年12月28日 14:15:06   作者:DayDayUp丶  
這篇文章主要介紹了Spring動態(tài)管理定時任務(wù)之ThreadPoolTaskScheduler解讀,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

Spring動態(tài)管理定時任務(wù)ThreadPoolTaskScheduler

Spring任務(wù)調(diào)度核心類ThreadPoolTaskScheduler,API文檔解釋如下:

Implementation of Spring's TaskScheduler interface, wrapping a native java.util.concurrent.ScheduledThreadPoolExecutor.

Spring的TaskScheduler接口的實現(xiàn),包裝了一個本地java.util.concurrent.ScheduledThreadPoolExecutor。

實現(xiàn)思路

注入調(diào)度類bean,初始化一個ConcurrentHashMap容器,用來保存多個定時任務(wù)的狀態(tài),每一個任務(wù)的運(yùn)行狀態(tài)被封裝在ScheduledFuture中,借此類可取消對應(yīng)的定時任務(wù)。

import java.time.LocalDateTime;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
 
import javax.annotation.Resource;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
 
import com.cjia.spidercommon.model.SpiderJob;
import com.cjia.spiderjob.mapper.SpiderJobMapper;
 
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
 
/**
 * 用來管理(啟動、停止、新增、刪除、更新編輯、查看運(yùn)行狀態(tài))定時任務(wù)(增量任務(wù))
 */
@Slf4j
@RestController
@RequestMapping("spiderJob/cron")
public class CronJobController extends SpiderJobController {
 
    @Autowired
    private ThreadPoolTaskScheduler threadPoolTaskScheduler;
 
    private Map<Integer, ScheduledFuture<?>> futureMap = new ConcurrentHashMap<>();
 
    @Resource
    private SpiderJobMapper spiderJobMapper;
 
    @Bean
    public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
        return new ThreadPoolTaskScheduler();
    }
 
    /**
     * 啟動單個定時任務(wù)
     */
    @RequestMapping("/start/{jobId}")
    public String start(@PathVariable Integer jobId) {
        SpiderJob job = spiderJobMapper.selectById(jobId);
        if (job == null) {
            log.warn("任務(wù)[{}]已不存在,無法啟動!", jobId);
            return "任務(wù)[" + jobId + "]已不存在,無法啟動!";
        }
        int enable = job.getEnable();
        if (enable == 0) {
            log.warn("任務(wù)[{}]已被禁用,無法啟動!", jobId);
            return "任務(wù)[" + jobId + "]已被禁用,無法啟動!";
        }
        // 檢測該任務(wù)是否已在運(yùn)行調(diào)度中
        if (futureMap.get(jobId) != null) {
            log.warn("任務(wù)[{}]已在調(diào)度運(yùn)行,無法重復(fù)啟動!", jobId);
            return "任務(wù)[" + jobId + "]已在調(diào)度運(yùn)行,無法重復(fù)啟動!";
        }
        String cron = job.getCron();
        // TODO check cron
        ScheduledFuture<?> future = threadPoolTaskScheduler.schedule(new MyRunnable(job), new CronTrigger(cron));
        log.info("任務(wù)[{}]已被啟動!", jobId);
        futureMap.put(jobId, future);
        return "任務(wù)[" + jobId + "]已被啟動!";
    }
 
    /**
     * 批量啟動定時任務(wù)
     */
    @RequestMapping("/startBatch/{jobIds}")
    public String startBatch(@PathVariable String jobIds) {
        // TODO jobIds valid
        String[] jobIdsArr = jobIds.split(",");
        StringBuffer sb = new StringBuffer();
        for (String jobId : jobIdsArr) {
            String result = start(Integer.valueOf(jobId));
            sb.append(result).append("<br>");
        }
        return sb.toString();
    }
 
    /**
     * 停止單個定時任務(wù)
     */
    @RequestMapping("/stop/{jobId}")
    public String stop(@PathVariable Integer jobId) {
        // 檢測該任務(wù)是否已在運(yùn)行調(diào)度中
        ScheduledFuture<?> future = futureMap.get(jobId);
        if (future == null) {
            log.warn("任務(wù)[{}]已不在調(diào)度中,無法停止!", jobId);
            return "任務(wù)[" + jobId + "]已不在調(diào)度中,無法停止!";
        } else {
            future.cancel(true);
            futureMap.remove(jobId);
            log.info("任務(wù)[{}]已被停止!", jobId);
            return "任務(wù)[" + jobId + "]已被停止!";
        }
    }
 
    /**
     * 批量停止定時任務(wù)
     */
    @RequestMapping("/stopBatch/{jobIds}")
    public String stopBatch(@PathVariable String jobIds) {
        // TODO jobIds valid
        String[] jobIdsArr = jobIds.split(",");
        StringBuffer sb = new StringBuffer();
        for (String jobId : jobIdsArr) {
            String result = stop(Integer.valueOf(jobId));
            sb.append(result).append("<br>");
        }
        return sb.toString();
    }
 
    /**
     * 查看當(dāng)前時刻調(diào)度中的定時任務(wù)
     */
    @RequestMapping("/status")
    public String getAllStatus() {
        Set<Integer> runningKeys = futureMap.keySet();
        return "當(dāng)前正在調(diào)度的任務(wù)列表:" + runningKeys.toString();
    }
 
    @Data
    private class MyRunnable implements Runnable {
        private SpiderJob job;
 
        public MyRunnable(SpiderJob job) {
            this.job = job;
        }
 
        @Override
        public void run() {
            log.info("運(yùn)行定時任務(wù)[{}: {}] at {}!", job.getId(), job.getBizName(), LocalDateTime.now());
            executeIncrementJob(job.getBizName());
        }
    }
 
}

ThreadPoolTaskScheduler 定時任務(wù)實現(xiàn)

org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler定時任務(wù)調(diào)度線程池

CREATE TABLE `sys_job` (
  `id` bigint(20) NOT NULL COMMENT '任務(wù)key',
  `job_name` varchar(64) NOT NULL COMMENT '任務(wù)名稱',
  `bean_class` varchar(128) NOT NULL COMMENT '類路徑',
  `cron_expression` varchar(64) NOT NULL COMMENT 'cron表達(dá)式',
  `status` tinyint(1) NOT NULL COMMENT '狀態(tài)值 @JobStatusEnum 詳見具體枚舉類',
  `is_deleted` tinyint(1) DEFAULT '0' COMMENT '刪除標(biāo)識 1是 0否',
  `create_time` datetime DEFAULT NULL,
  `update_time` datetime DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
@Configuration
@Slf4j
public class SchedulingConfigure {

    @Bean
    public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
        log.info("開始創(chuàng)建定時任務(wù)調(diào)度線程池");
        ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
        threadPoolTaskScheduler.setPoolSize(20);
        threadPoolTaskScheduler.setThreadNamePrefix("schedule-task-");
        threadPoolTaskScheduler.setWaitForTasksToCompleteOnShutdown(true);
        threadPoolTaskScheduler.setAwaitTerminationSeconds(60);
        log.info("創(chuàng)建定時任務(wù)調(diào)度線程池完成!");
        return threadPoolTaskScheduler;
    }
}
public enum JobStatusEnum {

    /**
     * 未加入調(diào)度器
     */
    NOT_SCHEDULE(0, "未加入調(diào)度器"),

    /**
     * 加入調(diào)度器,但未運(yùn)行
     */
    SCHEDULED_BUT_NOT_RUNNING(1, "加入調(diào)度器,但未運(yùn)行"),

    /**
     * 從調(diào)度器中已刪除
     */
    DELETED(2, "從調(diào)度器中已刪除"),
    ;

    private Integer status;

    private String detail;

    JobStatusEnum(Integer status, String detail) {
        this.status = status;
        this.detail = detail;
    }

    public Integer getStatus() {
        return status;
    }

    public void setStatus(Integer status) {
        this.status = status;
    }

    public String getDetail() {
        return detail;
    }

    public void setDetail(String detail) {
        this.detail = detail;
    }
}
@Component
@Slf4j
public class ScheduledJobService {

    private final ReentrantLock lock = new ReentrantLock();

    @Autowired
    private ThreadPoolTaskScheduler threadPoolTaskScheduler;
    @Autowired
    private SysJobService jobService;
    @Autowired
    private SpringBeanUtils springBeanUtils;

    /**
     * 已經(jīng)加入調(diào)度器的任務(wù)map
     */
    private final ConcurrentHashMap<Long, ScheduledFuture<?>> scheduledFutureMap = new ConcurrentHashMap<>();

    /**
     * 初始化啟動任務(wù)
     *
     * @param sysJobs 數(shù)據(jù)庫任務(wù)集合
     */
    public void initAllJob(List<SysJob> sysJobs) {
        if (CollectionUtils.isEmpty(sysJobs)) {
            return;
        }
        for (SysJob sysJob : sysJobs) {
            if (JobStatusEnum.NOT_SCHEDULE.getStatus().equals(sysJob.getStatus())
                    || JobStatusEnum.DELETED.getStatus().equals(sysJob.getStatus())
                    || this.isScheduled(sysJob.getId())) {
                // 任務(wù)初始化狀態(tài)或已刪除或已加載到調(diào)度器中
                continue;
            }
            // 將任務(wù)加入調(diào)度器
            this.doScheduleJob(sysJob);
        }
    }

    /**
     * 啟動任務(wù)
     *
     * @param jobId job主鍵id
     */
    public void start(Long jobId) {
        log.info("啟動任務(wù):-> jobId_{}", jobId);
        // 加入調(diào)度器
        schedule(jobId);
        log.info("啟動任務(wù)結(jié)束:-> jobId_{}", jobId);
        // 更新任務(wù)狀態(tài)
        jobService.updateJobStatus(jobId, JobStatusEnum.SCHEDULED_BUT_NOT_RUNNING.getStatus());
    }

    /**
     * 停止任務(wù)
     *
     * @param jobId job主鍵id
     */
    public void stop(Long jobId) {
        log.info("停止任務(wù):-> jobId_{}", jobId);
        // 取消任務(wù)
        cancel(jobId);
        log.info("停止任務(wù)結(jié)束:-> jobId_{}", jobId);
        // 更新表中任務(wù)狀態(tài)為已停止
        jobService.updateJobStatus(jobId, JobStatusEnum.NOT_SCHEDULE.getStatus());
    }

    /**
     * 移除任務(wù)
     *
     * @param jobId job主鍵id
     */
    public void remove(Long jobId) {
        log.info("移除任務(wù):-> jobId_{}", jobId);
        // 取消任務(wù)
        cancel(jobId);
        log.info("移除任務(wù)結(jié)束:-> jobId_{}", jobId);
        // 更新表中任務(wù)狀態(tài)為已刪除
        jobService.updateJobStatus(jobId, JobStatusEnum.DELETED.getStatus());
    }

    /**
     * 取消
     *
     * @param jobId 工作id
     */
    private void cancel(Long jobId) {
        // 任務(wù)是否存在
        if (scheduledFutureMap.containsKey(jobId)) {
            ScheduledFuture<?> scheduledFuture = scheduledFutureMap.get(jobId);
            if (!scheduledFuture.isCancelled()) {
                // 取消調(diào)度
                scheduledFuture.cancel(true);
            }
        }
    }

    private void schedule(Long jobId) {
        // 添加鎖,只允許單個線程訪問,防止任務(wù)啟動多次
        lock.lock();
        try {
            if (isScheduled(jobId)) {
                log.error("任務(wù)jobId_{}已經(jīng)加入調(diào)度器,無需重復(fù)操作", jobId);
                return;
            }
            // 通過jobKey查詢jobBean對象
            SysJob sysJob = jobService.getById(jobId);
            // 啟動定時任務(wù)
            doScheduleJob(sysJob);
        } finally {
            // 釋放鎖資源
            lock.unlock();
        }
    }

    /**
     * 執(zhí)行啟動任務(wù)
     *
     * @param sysJob 任務(wù)實體類對象
     */
    private void doScheduleJob(SysJob sysJob) {
        Long jobId = sysJob.getId();
        String beanClass = sysJob.getBeanClass();
        String jobName = sysJob.getJobName();
        String cron = sysJob.getCronExpression();
        // 從Spring中獲取目標(biāo)的job業(yè)務(wù)實現(xiàn)類
        ScheduledJob scheduledJob = parseFrom(beanClass);
        if (scheduledJob == null) {
            return;
        }
        scheduledJob.setJobId(jobId);
        scheduledJob.setJobName(jobName);

        ScheduledFuture<?> scheduledFuture = threadPoolTaskScheduler.schedule(scheduledJob,
                triggerContext -> {
                    CronTrigger cronTrigger = new CronTrigger(cron);
                    return cronTrigger.nextExecutionTime(triggerContext);
                });

        log.info("任務(wù)加入調(diào)度器 -> jobId:{},jobName:{}", jobId, jobName);

        // 將啟動的任務(wù)放入map
        assert scheduledFuture != null;
        scheduledFutureMap.put(jobId, scheduledFuture);
    }

    /**
     * 任務(wù)是否已經(jīng)進(jìn)入調(diào)度器
     *
     * @param jobId 任務(wù)主鍵key
     * @return {@link Boolean}
     */
    private Boolean isScheduled(Long jobId) {
        if (scheduledFutureMap.containsKey(jobId)) {
            return !scheduledFutureMap.get(jobId).isCancelled();
        }
        return false;
    }

    private ScheduledJob parseFrom(String beanClass) {
        try {
            Class<?> clazz = Class.forName(beanClass);
            return (ScheduledJob) springBeanUtils.getBean(clazz);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }
}
@Component
public class SpringBeanUtils implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        SpringBeanUtils.applicationContext = applicationContext;
    }

    /**
     * 獲取applicationContext
     */
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    /**
     * 通過name獲取 Bean.
     */
    public  Object getBean(String name) {
        return getApplicationContext().getBean(name);
    }

    /**
     * 通過class獲取Bean.
     */
    public  <T> T getBean(Class<T> clazz) {
        return getApplicationContext().getBean(clazz);
    }

    /**
     * 通過name,以及Clazz返回指定的Bean
     */
    public  <T> T getBean(String name, Class<T> clazz) {
        return getApplicationContext().getBean(name, clazz);
    }
}
@Data
public abstract class ScheduledJob implements Runnable {
    
    /**
    * 任務(wù)主鍵id
    */
    private Long jobId;
    
    /**
    * 任務(wù)名
    */
    private String jobName;
}

@Component
public class SchedulerTestDemo extends ScheduledJob {

    @Override
    public void run() {
        System.out.println("我是定時任務(wù)要執(zhí)行的類..");
        System.out.println(SchedulerTestDemo.class.getName() + ":" + LocalDateTime.now());
    }

}
/**
 * 項目啟動時,將數(shù)據(jù)庫中job定時任務(wù)加載
 */
@Component
public class GrapeApplicationListener {

    private final ScheduledJobService scheduledJobService;
    private final ISysJobService sysJobService;

    public GrapeApplicationListener(ISysJobService sysJobService, ScheduledJobService scheduledJobService) {
        this.sysJobService = sysJobService;
        this.scheduledJobService = scheduledJobService;
    }

    @PostConstruct
    public void initStartJob() {
    	// 初始化job
        scheduledJobService.initAllJob(sysJobService.list());
    }
}
@SpringBootApplication(scanBasePackages = {"com.example.grape"})
@MapperScan("com.example.grape.dao.mapper")
@EnableScheduling
public class GrapeApplication {

    public static void main(String[] args) {
        SpringApplication.run(GrapeApplication.class, args);
    }

}

總結(jié)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • SpringBoot中自定義首頁(默認(rèn)頁)及favicon的方法

    SpringBoot中自定義首頁(默認(rèn)頁)及favicon的方法

    這篇文章主要介紹了SpringBoot中如何自定義首頁(默認(rèn)頁)及favicon,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-08-08
  • SpringBoot中的異步執(zhí)行方法詳解

    SpringBoot中的異步執(zhí)行方法詳解

    這篇文章主要介紹了SpringBoot中的異步執(zhí)行方法詳解,ThreadpoolTaskExecutor不需要手動的創(chuàng)建當(dāng)前線程池,但往往我們還是會手動指定,具體原因看源碼就可以自有判斷,需要的朋友可以參考下
    2023-10-10
  • 如何在32位Windows系統(tǒng)下安裝Java

    如何在32位Windows系統(tǒng)下安裝Java

    這篇文章主要介紹了如何在32位Windows系統(tǒng)下安裝Java,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-04-04
  • Springboot Tomcat APR模式詳解和實踐記錄

    Springboot Tomcat APR模式詳解和實踐記錄

    這篇文章主要介紹了Springboot Tomcat APR模式詳解和實踐記錄,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2025-04-04
  • 設(shè)計模式之原型模式_動力節(jié)點Java學(xué)院整理

    設(shè)計模式之原型模式_動力節(jié)點Java學(xué)院整理

    這篇文章主要介紹了設(shè)計模式之原型模式,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-08-08
  • mybatis使用Integer類型查詢可能出現(xiàn)的問題

    mybatis使用Integer類型查詢可能出現(xiàn)的問題

    這篇文章主要介紹了mybatis使用Integer類型查詢可能出現(xiàn)的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • 淺談JAVA 異常對于性能的影響

    淺談JAVA 異常對于性能的影響

    Java的異常處理為什么會影響性能?異常開銷很大。那么,這是不是就意味著您不該使用異常?當(dāng)然不是。但是,何時應(yīng)該使用異常,何時又不應(yīng)該使用異常呢?不幸的是,答案不是一下子就說得清楚的,我們來詳細(xì)探討下。
    2015-05-05
  • Java?將Excel轉(zhuǎn)為UOS的操作方法

    Java?將Excel轉(zhuǎn)為UOS的操作方法

    以.uos為后綴的文件,表示Uniform?Office?Spreadsheet文件,是一種國產(chǎn)的辦公文件格式,該格式以統(tǒng)一辦公格式(UOF)創(chuàng)建,使用XML和壓縮保存電子表格,這篇文章主要介紹了Java?將Excel轉(zhuǎn)為UOS,需要的朋友可以參考下
    2022-09-09
  • 基于java中集合的概念(詳解)

    基于java中集合的概念(詳解)

    下面小編就為大家?guī)硪黄趈ava中集合的概念(詳解)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-09-09
  • Java StringTokenizer分隔符拆分字符串

    Java StringTokenizer分隔符拆分字符串

    Java中的StringTokenizer類用于將一個字符串分解成標(biāo)記,本文主要介紹了Java StringTokenizer分隔符拆分字符串,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-08-08

最新評論

平昌县| 永州市| 分宜县| 东安县| 定日县| 花莲市| 赞皇县| 闸北区| 昔阳县| 金寨县| 三河市| 阳朔县| 卫辉市| 石阡县| 营口市| 奎屯市| 漳州市| 黎平县| 长宁区| 富宁县| 夹江县| 田东县| 台北市| 安岳县| 皮山县| 深州市| 甘肃省| 额尔古纳市| 武冈市| 绥阳县| 万荣县| 永州市| 西丰县| 宁强县| 凭祥市| 望江县| 全椒县| 中西区| 冕宁县| 永州市| 安顺市|