序言
對于定時任務,在SpringBoot中只需要使用@Scheduled 這個注解就能夠滿足需求,它的出現也給我們帶了很大的方便,我們只要加上該注解,并且根據需求設定好就可以使用定時任務了,
但是,我們需要注意的是,@Scheduled 并不一定會按時執行,
因為使用@Scheduled 的定時任務雖然是異步執行的,但是,不同的定時任務之間并不是并行的!!!!!!!!
在其中一個定時任務沒有執行完之前,其他的定時任務即使是到了執行時間,也是不會執行的,它們會進行排隊,
也就是如果你想你不同的定時任務互不影響,到時間就會執行,那么你最好將你的定時任務方法自己搞成異步方法,這樣,定時任務其實就相當于呼叫了一個執行緒執行任務,一瞬間就結束了,比如使用:@Async
當然,也可以勉強將你的定時任務當做都會定時執行,但是,作為一個合格的程式員
那么,如何將@Scheduled實作的定時任務變成異步的呢?此時你需要對@Scheduled進行執行緒池配置,
配置示例
package com.java.navtool.business.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
/**
* @author :mmzsblog.cn
* @date :Created in 2021/7/27 17:46
* @description:spring-boot 多執行緒 @Scheduled注解 并發定時任務的解決方案
* @modified By:
* @version:
*/
@Configuration
@EnableScheduling
public class ScheduleConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(taskExecutor());
}
public static final String EXECUTOR_SERVICE = "scheduledExecutor";
@Bean(EXECUTOR_SERVICE)
public TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 設定核心執行緒數
executor.setCorePoolSize(Runtime.getRuntime().availableProcessors());
// 設定最大執行緒數
executor.setMaxPoolSize(Runtime.getRuntime().availableProcessors() * 10);
// 設定佇列容量
executor.setQueueCapacity(Runtime.getRuntime().availableProcessors() * 10);
// 設定執行緒活躍時間(秒)
executor.setKeepAliveSeconds(10);
// 設定默認執行緒名稱
executor.setThreadNamePrefix("scheduled-");
// 設定拒絕策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 等待所有任務結束后再關閉執行緒池
executor.setWaitForTasksToCompleteOnShutdown(true);
return executor;
}
}
附帶介紹一下執行緒池的幾個引數,需要徹底搞懂,不要死記硬背哦!
執行緒池引數
- 1、corePoolSize(必填):核心執行緒數,
- 2、maximumPoolSize(必填):最大執行緒數,
- 3、keepAliveTime(必填):執行緒空閑時長,如果超過該時長,非核心執行緒就會被回收,
- 4、unit(必填):指定keepAliveTime的時間單位,常用的有:TimeUnit.MILLISECONDS(毫秒)、TimeUnit.SECONDS(秒)、TimeUnit.MINUTES(分),
- 5、workQueue(必填):任務佇列,通過執行緒池的execute()方法提交的Runnable物件將存盤在該佇列中,
- 6、threadFactory(可選):執行緒工廠,一般就用默認的,
- 7、handler(可選):拒絕策略,當執行緒數達到最大執行緒數時就要執行飽和策略,
說下核心執行緒數和最大執行緒數的區別:
拒絕策略可選值:
- 1、AbortPolicy(默認):放棄任務并拋出RejectedExecutionException例外,
- 2、CallerRunsPolicy:由呼叫執行緒處理該任務,
- 3、DiscardPolicy:放棄任務,但是不拋出例外,可以配合這種模式進行自定義的處理方式,
- 4、DiscardOldestPolicy:放棄佇列最早的未處理任務,然后重新嘗試執行任務,
執行緒池執行流程:
上個流程圖,先試著自己看下能不能看懂:

簡短的總結下執行緒池執行流程:
- 1、一個任務提交到執行緒池后,如果當前的執行緒數沒達到核心執行緒數,則新建一個執行緒并且執行新任務,注意一點,這個新任務執行完后,該執行緒不會被銷毀;
- 2、如果達到了,則判斷任務佇列滿了沒,如果沒滿,則將任務放入任務佇列;
- 3、如果滿了,則判斷當前執行緒數量是否達到最大執行緒數,如果沒達到,則創建新執行緒來執行任務,注意,如果執行緒池中執行緒數量大于核心執行緒數,每當有執行緒超過了空閑時間,就會被銷毀,直到執行緒數量不大于核心執行緒數;
- 4、如果達到了最大執行緒數,并且任務佇列滿了,就會執行飽和策略;
原創公眾號:Java學習之道
個人博客 : www.mmzsblog.cn
喜歡就推薦一下,因為你的參與是我在寫作道路上的最強動力,
本文著作權歸作者淼淼之森和博客園共有,歡迎轉載,
但須在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/449742.html
標籤:Java
