java写一个服务定时采集数据_java实现定时任务解决方案
1. 總結(jié)常見的實(shí)現(xiàn)定時(shí)任務(wù)的幾種方法
thread實(shí)現(xiàn) 【原理:通過創(chuàng)建一個(gè)線程,讓他在while循環(huán)里面一直運(yùn)行,用sleep() 方法讓其休眠從而達(dá)到定時(shí)任務(wù)的效果。】
Timer類
ScheduledExcecutorService類
使用spring的 spring-task 實(shí)現(xiàn)
Quartz
以下演示幾種實(shí)現(xiàn)方式:每隔一秒打印一次hello world
1.1 thread實(shí)現(xiàn)
public static void main(String[] args) {
final long timeInterval = 1000;
Runnable runnable = new Runnable() {
@Override
public void run() {
while (true) {
System.out.println("hello world");
try {
Thread.sleep(timeInterval);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
Thread thread = new Thread(runnable);
thread.start();
}
1.2 Timer類實(shí)現(xiàn)
Timer是jdk中自帶的一個(gè)定時(shí)器工具,使用的時(shí)候會(huì)在主線程之外起一個(gè)單獨(dú)的線程執(zhí)行指定的計(jì)劃任務(wù),可以指定執(zhí)行一次或者反復(fù)執(zhí)行多次。但封裝任務(wù)的類是TimerTask類(實(shí)際該類是一個(gè)抽象類,執(zhí)行任務(wù)的代碼要放在該類的子類中)。
TimerTask是一個(gè)實(shí)現(xiàn)了Runnable接口的抽象類,代表一個(gè)可以被Timer執(zhí)行的任務(wù)。
構(gòu)造方法:
成員方法:
public static void main(String[] args) {
TimerTask task = new TimerTask() {
@Override
public void run() {
System.out.println("Hello!Word!");
}
};
Timer timer = new Timer();
long delay = 0;
long intevalPeriod = 1 * 1000;
timer.scheduleAtFixedRate(task, delay, intevalPeriod);
}
schedule 與 scheduleAtFixedRate區(qū)別:
schedule會(huì)保證任務(wù)的間隔是按照定義的period參數(shù)嚴(yán)格執(zhí)行的,如果某一次調(diào)度時(shí)間比較長,那么后面的時(shí)間會(huì)順延,保證調(diào)度間隔都是period。
scheduleAtFixedRate是嚴(yán)格按照調(diào)度時(shí)間來的,如果某次調(diào)度時(shí)間太長了,那么會(huì)通過縮短間隔的方式保證下一次調(diào)度在預(yù)定時(shí)間執(zhí)行。
線程安全, 但只會(huì)單線程執(zhí)行, 如果執(zhí)行時(shí)間過長, 就錯(cuò)過下次任務(wù)了, 拋出異常時(shí), timerWork會(huì)終止
啟動(dòng)和取消任務(wù)是可以控制的
1.3 ScheduledExcecutorService類實(shí)現(xiàn)
ScheduledExecutorService是JDK1.5以后java.util.concurrent中的一個(gè)接口, 用于實(shí)現(xiàn)定時(shí)任務(wù)。
public static void main(String[] args) {
Runnable r1 = new Runnable() {
public void run() {
System.out.println("Hello Word");
}
};
ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
// 第二個(gè)參數(shù)為首次執(zhí)行的延時(shí)時(shí)間,第三個(gè)參數(shù)為定時(shí)執(zhí)行的間隔時(shí)間
service.scheduleAtFixedRate(r1, 3, 1, TimeUnit.SECONDS);// 3秒后開始執(zhí)行
}
他是通過線程池的方式執(zhí)行任務(wù),可以多線程執(zhí)行。
啟動(dòng)和取消任務(wù)是可以控制的
可以設(shè)定第一次的延遲時(shí)間
1.4 使用spring提供的 spring-task 實(shí)現(xiàn)
a) 只需要導(dǎo)入web的starter依賴
b) 在啟動(dòng)類上添加 @EnableScheduling 注解
c) 用 @Scheduled 注解開啟一個(gè)定時(shí)任務(wù)。
@Component
public class SchedulerTask {
private int count = 0;
/**
* @Author Smith
* @Description 設(shè)置每1秒執(zhí)行一次
* @Date 14:23 2019/1/24
* @Param
* @return void
**/
@Scheduled(cron = "*/1 * * * * ?") // 基于cron表達(dá)式實(shí)現(xiàn)
private void process(){
System.out.println("hello world " + (count++));
}
}
@Scheduled 該注解的常用參數(shù)說明【不基于cron表達(dá)式實(shí)現(xiàn)的時(shí)候】:
fixedRate 表示任務(wù)執(zhí)行之間的時(shí)間間隔,具體是指兩次任務(wù)的開始時(shí)間間隔,即第二次任務(wù)開始時(shí),第一次任務(wù)可能還沒結(jié)束。
fixedDelay 表示任務(wù)執(zhí)行之間的時(shí)間間隔,具體是指本次任務(wù)結(jié)束到下次任務(wù)開始之間的時(shí)間間隔。
initialDelay 表示首次任務(wù)啟動(dòng)的延遲時(shí)間。
所有時(shí)間的單位都是毫秒。
1.5 Quartz
參考
源碼
Quartz是OpenSymphony開源組織在Job scheduling領(lǐng)域又一個(gè)開源項(xiàng)目,它可以與J2EE與J2SE應(yīng)用程序相結(jié)合也可以單獨(dú)使用。Quartz可以用來創(chuàng)建簡單或?yàn)檫\(yùn)行十個(gè),百個(gè),甚至是好幾萬個(gè)Jobs這樣復(fù)雜的程序。
Quartz默認(rèn)是多線程異步執(zhí)行,單個(gè)任務(wù)時(shí),在上一個(gè)調(diào)度未完成時(shí),下一個(gè)調(diào)度時(shí)間到時(shí),會(huì)另起一個(gè)線程開始新的調(diào)度。
Quartz支持集群定時(shí)任務(wù)
Quartz與Spring Task區(qū)別
Quartz默認(rèn)多線程異步執(zhí)行,Task默認(rèn)單線程同步執(zhí)行。
Quartz單個(gè)任務(wù)時(shí),在上一個(gè)調(diào)度未完成時(shí),下一個(gè)調(diào)度時(shí)間到時(shí),會(huì)另起一個(gè)線程開始新的調(diào)度。Task單個(gè)任務(wù)時(shí),當(dāng)前次的調(diào)度完成后,再執(zhí)行下一次任務(wù)調(diào)度。
Quartz多個(gè)任務(wù)時(shí),任務(wù)之間沒有直接影響,多任務(wù)執(zhí)行的快慢取決于CPU的性能。Task多個(gè)任務(wù)時(shí),一個(gè)任務(wù)執(zhí)行完成后才會(huì)執(zhí)行下一個(gè)任務(wù)。若需要任務(wù)能夠并發(fā)執(zhí)行,需手動(dòng)設(shè)置線程池
Quartz可以采用集群方式,分布式部署到多臺(tái)機(jī)器,分配執(zhí)行定時(shí)任務(wù)
兩者對(duì)比總結(jié):
1、實(shí)現(xiàn),Task注解實(shí)現(xiàn)方式,比較簡單。Quartz需要手動(dòng)配置Jobs。
2、任務(wù)執(zhí)行,Task默認(rèn)單線程串行執(zhí)行任務(wù),多任務(wù)時(shí)若某個(gè)任務(wù)執(zhí)行時(shí)間過長,后續(xù)任務(wù)會(huì)無法及時(shí)執(zhí)行。Quartz采用多線程,無這個(gè)問題。
3、調(diào)度,Task采用順序執(zhí)行,若當(dāng)前調(diào)度占用時(shí)間過長,下一個(gè)調(diào)度無法及時(shí)執(zhí)行;
4、Quartz采用異步,下一個(gè)調(diào)度時(shí)間到達(dá)時(shí),會(huì)另一個(gè)線程執(zhí)行調(diào)度,不會(huì)發(fā)生阻塞問題,但調(diào)度過多時(shí)可能導(dǎo)致數(shù)據(jù)處理異常
5、部署,Quartz可以采用集群方式,分布式部署到多臺(tái)機(jī)器,分配執(zhí)行定時(shí)任務(wù)
Quartz 核心概念:
a) Job 表示一個(gè)工作,要執(zhí)行的具體內(nèi)容。此接口中只有一個(gè)方法。Task多個(gè)任務(wù)時(shí),一個(gè)任務(wù)執(zhí)行完成后才會(huì)執(zhí)行下一個(gè)任務(wù)。若需要任務(wù)能夠并發(fā)執(zhí)行,需手動(dòng)設(shè)置線程池。
void execute(JobExecutionContext context)
b) JobDetail 表示一個(gè)具體的可執(zhí)行的調(diào)度程序,Job 是這個(gè)可執(zhí)行程調(diào)度程序所要執(zhí)行的內(nèi)容,另外 JobDetail 還包含了這個(gè)任務(wù)調(diào)度的方案和策略。
c) Trigger 代表一個(gè)調(diào)度參數(shù)的配置,什么時(shí)候去調(diào)。
d) Scheduler 代表一個(gè)調(diào)度容器,一個(gè)調(diào)度容器中可以注冊(cè)多個(gè) JobDetail 和 Trigger。當(dāng) Trigger 與 JobDetail 組合,就可以被 Scheduler 容器調(diào)度了。
Spring Boot整合Quartz:
導(dǎo)入Quartz依賴
org.springframework.boot
spring-boot-starter-quartz
編寫任務(wù)類
public class Task implements Job {
// 任務(wù)類不能直接注入Bean,若想注入Bean需要配置第4步
@Autowired
private TestService service;
private void before(){
System.out.println("定時(shí)任務(wù)開始");
}
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
service.testDemo();
System.out.println("hello quartz");
}
private void afer(){
System.out.println("定時(shí)任務(wù)結(jié)束");
}
}
★ 任務(wù)類不能直接注入Bean,若想注入Bean需要配置第4步 ★
編寫Quartz配置
@Configuration
public class QuartzConfig {
@Bean
public JobDetailFactoryBean jobDetailFactoryBean() {
JobDetailFactoryBean factory = new JobDetailFactoryBean();
//關(guān)聯(lián)我們自己的Job類
factory.setJobClass(Task.class);
return factory;
}
@Bean
public CronTriggerFactoryBean cronTriggerFactoryBean(JobDetailFactoryBean jobDetailFactoryBean) {
CronTriggerFactoryBean factory = new CronTriggerFactoryBean();
factory.setJobDetail(jobDetailFactoryBean.getObject());
//設(shè)置觸發(fā)時(shí)間
factory.setCronExpression("0/2 * * * * ?");
return factory;
}
@Bean
public SchedulerFactoryBean schedulerFactoryBean(CronTriggerFactoryBean cronTriggerFactoryBean, MyAdaptableJobFactory jobFactory) {
SchedulerFactoryBean factory = new SchedulerFactoryBean();
//關(guān)聯(lián)trigger
factory.setTriggers(cronTriggerFactoryBean.getObject());
factory.setJobFactory(jobFactory);
return factory;
}
}
編寫配置【用于任務(wù)類能注入我們的bean】
@Component
public class MyAdaptableJobFactory extends AdaptableJobFactory {
// 可以將一個(gè)對(duì)象添加到SpringIOC 容器中,并且完成該對(duì)象注入
@Autowired
private AutowireCapableBeanFactory autowireCapableBeanFactory;
/**
* 該方法需要將實(shí)例化的任務(wù)對(duì)象手動(dòng)的添加到springIOC 容器中并且完成對(duì)象的注入
*/
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
Object obj = super.createJobInstance(bundle);
//將obj 對(duì)象添加Spring IOC 容器中,并完成注入
this.autowireCapableBeanFactory.autowireBean(obj);
return obj;
}
}
2 Quartz[群集環(huán)境]
使用quartz實(shí)現(xiàn)定時(shí)任務(wù)[單機(jī)版],若是部署多臺(tái)機(jī)器,那么到了時(shí)間點(diǎn),多臺(tái)服務(wù)器便會(huì)同時(shí)均開始執(zhí)行定時(shí)任務(wù)。
Quartz是能適用于分布式集群環(huán)境的,在同一時(shí)間只會(huì)有一臺(tái)機(jī)器執(zhí)行定時(shí)任務(wù)。
Quartz 中集群如何工作:
一個(gè) Quartz 集群中的每個(gè)節(jié)點(diǎn)是一個(gè)獨(dú)立的 Quartz 應(yīng)用,它又管理著其他的節(jié)點(diǎn)。意思是你必須對(duì)每個(gè)節(jié)點(diǎn)分別啟動(dòng)或停止。不像許多應(yīng)用服務(wù)器的集群,獨(dú)立的 Quartz 節(jié)點(diǎn)并不與另一其的節(jié)點(diǎn)或是管理節(jié)點(diǎn)通信。Quartz 應(yīng)用是通過數(shù)據(jù)庫表來感知到另一應(yīng)用的。離開了db將無法感知
2.1 導(dǎo)入依賴
org.springframework.boot
spring-boot-starter-quartz
2.2 數(shù)據(jù)庫建表
到官網(wǎng)下載
下載之后解壓,進(jìn)入如下目錄,創(chuàng)建數(shù)據(jù)庫表:
11張表功能說明:
總結(jié)
以上是生活随笔為你收集整理的java写一个服务定时采集数据_java实现定时任务解决方案的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java 日期只计算年月日大小_Java
- 下一篇: mysql备份到邮箱,备份网站mysql