java目前常用的幾種定時任務
一、JDK自帶的Timer
Timer是jdk中提供的一個定時器工具,使用的時候會在主線程之外起一個單獨的線程執行指定的計划任務,可以指定執行一次或者反復執行多次。
TimerTask是一個實現了Runnable接口的抽象類,代表一個可以被Timer執行的任務。
1 import org.junit.Test;
2 import java.util.Timer;
3 import java.util.TimerTask;
4
5 public class TimerTest {
6 @Test
7 public void test(){
8 Timer timer = new Timer();
9 TimerTask timerTask = new TimerTask() {
10 @Override
11 public void run() {
12 System.out.println("當前時間");//具體的任務
13 }
14 };
15 timer.schedule(timerTask1,1000,1000);//任務,開始時間ms,間隔ms
16 System.out.println("start");
17 try {
18 Thread.sleep(2000);//不停兩秒,顯示不出來,因為test情況下當前用戶線程結束,可是定時任務1s還沒開始,就被終止
19 }catch (Exception e) {
20
21 }
22 System.out.println("end");
23 }
24 }
終止timer的方式
- 調用timer的cancle方法,
- 把timer線程設置成daemon線程,(new Timer(true)創建daemon線程),在jvm里,如果所有用戶線程結束,那么守護線程也會被終止,不過這種方法一般不用。
- 當所有任務執行結束后,刪除對應timer對象的引用,線程也會被終止。
- 調用System.exit方法終止程序
注意點
- 每一個Timer僅對應唯一一個線程。
- Timer不保證任務執行的十分精確, schedule如果某一次調度時間比較長,那么后面的時間會順延和scheduleAtFixedRate(嚴格按照調度時間來的,如果某次調度時間太長了,那么會通過縮短間隔的方式保證下一次調度在預定時間執行)會有不同的時間差。
- Timer類的線程安全的
- jdk1.5之后,ScheduledExecutorService代替了Timer來實現任務調度,加入了線程池等特性。
二、spring的Task
Task底層的實現,使用的ScheduledExecutorService。
2.1、注解的形式
使用@EnableScheduling啟動定時任務注解解析,之后@Schedule寫在執行的任務上即可
[cron表達式詳解](https://www.jianshu.com/p/1defb0f22ed1)
2.2、直接代碼的形式
1 @EnableScheduling
2 public class Task {
3
4 @Scheduled(zone = "Asia/Beijing",cron = "0/10 * * * * * *")//zone表示時區
5 public void schedule4(){
6 }
7 /*
8 fixedDelay對應的fixedDelayString支持字符串形式、占位符${}|#{}
9 */
10 @Scheduled(fixedDelay = 5000)//上一次執行完畢時間點之后多長時間再執行
11 public void schedule1(){
12 }
13 @Scheduled(fixedRate = 5000)//上一次開始執行時間點之后多長時間再執行
14 public void schedule2(){
15 }
16 @Scheduled(initialDelay = 5000)//第一次延遲多長時間后再執行
17 public void schedule3(){
18 }
19
20 }
TaskScheduler的子類
-
ConcurrentTaskScheduler:以當前線程執行任務。如果任務簡單,可以直接使用這個類來執行。快捷方便。
-
DefaultManagedTaskScheduler:以當前線程執行任務,這是ConcurrentTaskScheduler的子類,添加了JNDI的支持。和ConcurrentTaskScheduler一樣的用法,需要使用JNDI可以單獨設置
-
ThreadPoolTaskScheduler:TaskScheduler接口的默認實現類,多線程定時任務執行。<font color=#0075EA>可以設置執行線程池數(默認一個線程),使用前必須得先調用initialize()【初始化方法】,有shutDown()方法,執行完后可以關閉線程</font>。
-
TimerManagerTaskScheduler:用於包裝CommonJ中的TimerManager接口。在使用CommonJ進行調度時使用。(沒有使用過)
三、Quartz
四、elastic-job分布式定時任務
基於Zookepper和Quartz開發,並且開源的Java分布式定時任務,解決Quartz不支持分布式的弊端,Elastic-Job采用分片的方式,是分布式調度解決方案。適用場景是:相對於流程比較簡單,但是任務可以拆分到多個線程去執行。 每個任務都使用獨立的線程池。
1 //注冊zookeeper
2 @Bean(initMethod = "init")
3 public ZookeeperRegistryCenter regCenter( final String serverList,final String namespace) {
4 return new ZookeeperRegistryCenter(new ZookeeperConfiguration(serverList, namespace));
5 }
1 //配置任務config
2 @Configuration
3 public class LoginOverdueJobConfig {
4 @Resource
5 private ZookeeperRegistryCenter regCenter;
6
7 @Resource
8 private JobEventConfiguration jobEventConfiguration;
9
10 private LiteJobConfiguration getLiteJobConfiguration(final Class<? extends SimpleJob> jobClass, final String cron, final int shardingTotalCount, final String shardingItemParameters) {
11 return LiteJobConfiguration.newBuilder(new SimpleJobConfiguration(JobCoreConfiguration.newBuilder(
12 jobClass.getName(), cron, shardingTotalCount).shardingItemParameters(shardingItemParameters).build(), jobClass.getCanonicalName())).overwrite(true).build();
13 }
14
15 @Bean(initMethod = "init")
16 public JobScheduler simpleCloudStorageJobScheduler(final LoginOverdueJob loginOverdueJob, @Value("${simpleJob.cron}") final String cron, @Value("${simpleJob.shardingTotalCount}") final int shardingTotalCount,
17 @Value("${simpleJob.shardingItemParameters}") final String shardingItemParameters) {
18 return new SpringJobScheduler(loginOverdueJob, regCenter, getLiteJobConfiguration(loginOverdueJob.getClass(), cron, shardingTotalCount, shardingItemParameters), jobEventConfiguration);
19 }
20 }
1 //任務執行函數
2 @Component
3 public class LoginOverdueJob implements SimpleJob {
4 public void execute(ShardingContext shardingContext) {
5
6 }
7 }