1. 程式人生 > >java中定時任務

java中定時任務

java中的定時任務, 使用java實現有3種方式:

1, 使用普通thread實現

複製程式碼
  @Test
  public void test1() {  
        // 單位: 毫秒
        final long timeInterval = 1000;  
        Runnable runnable = new Runnable() {  
            public void run() {  
                while (true) {  
                    // ------- code for task to run  
                    System.out
.println("Hello !!"); // ------- ends here try { Thread.sleep(timeInterval); } catch (InterruptedException e) { e.printStackTrace(); } } } }; Thread thread
= new Thread(runnable); thread.start(); }
複製程式碼

2, 使用timer實現: 可控制啟動或取消任務, 可指定第一次執行的延遲

  執行緒安全, 但只會單執行緒執行, 如果執行時間過長, 就錯過下次任務了, 丟擲異常時, timerWork會終止

複製程式碼
@Test
public void test2 () {  
      TimerTask task = new TimerTask() {  
          @Override  
          public void run() {  
             System.out.println(
"Hello !!!"); } }; Timer timer = new Timer(); long delay = 0; long intevalPeriod = 1 * 1000; // schedules the task to be run in an interval timer.scheduleAtFixedRate(task, delay, intevalPeriod); }
複製程式碼

3, 使用 ScheduledExcecutorService 實現

  ScheduledExecutorService 是java.util.concurrent種的額一個累, 用於實現定時任務

  它可以: 1, 通過執行緒池的方式執行任務

      2, 設定第一次的延遲事件

      3, 提供良好的約定, 設定時間間隔

複製程式碼
@Test
public void test() {
    Runnable runnable = new Runnable() {  
            public void run() {  
                System.out.println("Hello !!");  
            }  
        };  
        ScheduledExecutorService service = Executors  
                .newSingleThreadScheduledExecutor();  
        // 第二個引數為首次執行的延時時間,第三個引數為定時執行的間隔時間  
        service.scheduleAtFixedRate(runnable, 10, 1, TimeUnit.SECONDS);  
    }  
複製程式碼

4, 使用spring的 spring-task 實現

   第一種方式, 註解的方式實現

複製程式碼
@Target({java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.ANNOTATION_TYPE})  
@Retention(RetentionPolicy.RUNTIME)  
@Documented  
public @interface Scheduled  
{  
  public abstract String cron();  

  public abstract long fixedDelay();  

  public abstract long fixedRate();  
}  
fixedDelay: 設定間隔時間為 5000ms
fixedRate: 設定固定速率, 以固定速率5s來執行
cron="0 0 2 * * ? ": 使用時間表達式
複製程式碼

   第二種方式, 配置檔案配置的方式實現

 <task:scheduled-tasks>   
        <task:scheduled ref="taskJob" method="job1" cron="0 * * * * ?"/>   
</task:scheduled-tasks>  
  /* taskJob 為執行任務類, job1 為執行的函式*/
<context:component-scan base-package="com.wenbronk.mytask " />  

    2, 新增配置資訊    

<!—開啟這個配置,spring才能識別@Scheduled註解   -->  
    <task:annotation-driven scheduler="qbScheduler" mode="proxy"/>  
    <task:scheduler id="qbScheduler" pool-size="10"/> 

    3, 程式碼實現 

@Scheduled(fixedDelay = 5000)
public void doSomething() { 
    // something that should execute periodically
}

時間表達式

複製程式碼
一個cron表示式有至少6個(也可能7個)有空格分隔的時間元素。
按順序依次為
秒(0~59)
分鐘(0~59)
小時(0~23)
天(月)(0~31,但是你需要考慮你月的天數)
月(0~11)
天(星期)(1~7 1=SUN 或 SUN,MON,TUE,WED,THU,FRI,SAT)
年份(1970-2099)
複製程式碼

常用的表示式為: 

複製程式碼
0 0 10,14,16 * * ? 每天上午10點,下午2點,4點
0 0/30 9-17 * * ?   朝九晚五工作時間內每半小時
0 0 12 ? * WED 表示每個星期三中午12點 
"0 0 12 * * ?" 每天中午12點觸發 
"0 15 10 ? * *" 每天上午10:15觸發 
"0 15 10 * * ?" 每天上午10:15觸發 
"0 15 10 * * ? *" 每天上午10:15觸發 
"0 15 10 * * ? 2005" 2005年的每天上午10:15觸發 
"0 * 14 * * ?" 在每天下午2點到下午2:59期間的每1分鐘觸發 
"0 0/5 14 * * ?" 在每天下午2點到下午2:55期間的每5分鐘觸發 
"0 0/5 14,18 * * ?" 在每天下午2點到2:55期間和下午6點到6:55期間的每5分鐘觸發 
"0 0-5 14 * * ?" 在每天下午2點到下午2:05期間的每1分鐘觸發 
"0 10,44 14 ? 3 WED" 每年三月的星期三的下午2:10和2:44觸發 
"0 15 10 ? * MON-FRI" 週一至週五的上午10:15觸發 
"0 15 10 15 * ?" 每月15日上午10:15觸發 
"0 15 10 L * ?" 每月最後一日的上午10:15觸發 
"0 15 10 ? * 6L" 每月的最後一個星期五上午10:15觸發 
"0 15 10 ? * 6L 2002-2005" 2002年至2005年的每月的最後一個星期五上午10:15觸發 
"0 15 10 ? * 6#3" 每月的第三個星期五上午10:15觸發 
複製程式碼

5, 使用 第三方外掛 Quartz實現

 maven依賴

    <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>2.2.1</version>
        </dependency>

5. 1) 可以設定一個類, 繼承自 QuartzJobBean

 1, 配置檔案: 

複製程式碼
    <!-- 配置作業類 -->
    <bean name="job1" class="org.springframework.scheduling.quartz.JobDetailBean">
        <property name="jobClass" value="com.gy.Job1" />
        <property name="jobDataAsMap">
            <map>
                <entry key="timeout" value="0" />
            </map>
        </property>
    </bean>

    <!-- 配置觸發方式 -->
    <!-- simpleTrggerBean 只支援一種方式排程 -->
    <bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
        <property name="jobDetail" ref="job1" />
        <property name="startDelay" value="0" />  <!-- 排程工廠例項化後,經過0秒開始執行排程 -->
        <property name="repeatInterval" value="2000" />  <!-- 每2秒排程一次 -->
    </bean>


    <!-- 使用CronTrggerBean , 支援時間表達式 -->
    <bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
        <property name="jobDetail" ref="job1" />  
        <!-- 每天12點執行一次 -->
        <property name="cronExpression" value="0 0 12 * * ?" />
    </bean>
複製程式碼

  2, 配置排程工廠: 

複製程式碼
    <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="triggers">
            <list>
                <ref bean="cronTrigger" />
            </list>
        </property>
    </bean>
複製程式碼

   3, 定義作業類: 

複製程式碼
public class Job1 extends QuartzJobBean {
        private int timeout;
        private static int i = 0;
        // 排程工廠例項化後,經過timeout時間開始執行排程
        public void setTimeout(int timeout) {
            this.timeout = timeout;
        }
        /**
         * 要排程的具體任務
         */
        @Override
        protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
            System.out.println("定時任務執行中…");
        }
    }
複製程式碼

5.2) 直接寫一個普通類, 在配置中進行配置 

  任務類: 

複製程式碼
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;

/**
 * 定時刪除使用者收聽過的poi
 * @author wenbronk
 * @time 2017年3月28日  下午2:01:09  2017
 */
public class DelListenerPOIScheduler {

    @Autowired
    private StringRedisTemplate redisTemplate;

    public void doCheck() {
        System.out.println("定時任務執行了....");
    }

}
複製程式碼

配置檔案: 

複製程式碼
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
                        http://www.springframework.org/schema/tx
                        http://www.springframework.org/schema/tx/spring-tx-4.2.xsd
                        http://www.springframework.org/schema/aop
                        http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
                        http://www.springframework.org/schema/aop
                        http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
                        http://www.springframework.org/schema/mvc
                         http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd
                        http://www.springframework.org/schema/context
                        http://www.springframework.org/schema/context/spring-context-4.2.xsd">

    <!-- 配置作業類 -->
    <bean id="delRedisListenerHistory" class="com.iwhere.easy.travel.valid.DelListenerPOIScheduler" />

    <!-- 作業類描述, 使用方法排程 -->
    <bean id="methodInvoking"
        class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
        <property name="targetObject" ref="delRedisListenerHistory" />
        <property name="targetMethod" value="doCheck" />
    </bean>

    <!-- 觸發器, 使用定時觸發 -->
    <bean id="delTrigger"
        class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <property name="jobDetail" ref="methodInvoking" />
        <property name="cronExpression" value="0/10 * * * * ?" />
    </bean>

    <!-- 總排程器 -->
    <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="triggers">
            <list>
                <ref bean="delTrigger" />
            </list>
        </property>
    </bean>

</beans>
複製程式碼

6, 在springboot中實現定時任務: 

複製程式碼
package com.iwhere.base.scheduling;

import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;

/**
 * 整合定時任務
 * EnableScheduling 實現spring中的task功能
 * @Scheduled中配置時間表達式
 * @author 231
 *
 */
@Configuration        // 相當於配置beans, 
@EnableScheduling    // <task:*>, 讓spring進行任務排程
public class SchedulingConfig {

    @Scheduled(cron="0/20 * * * * ?")    // 20秒執行一次
    public void scheduler() {
        System.out.println("定時任務執行了");
    }

}
複製程式碼

 7, Springboot 整合 quartz

為什麼非要整合呢, 因為quartz支援叢集定時任務, 現在還用不到, 防止以後用到

1, 配置quartz的配置資訊類

複製程式碼
package com.iwhere.easy.travel.timeschedule;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
import org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
/**
 * quartz的配置資訊
 * @author wenbronk
 * @time 2017年3月29日  下午5:20:29  2017
 */
@Configuration 
public class TimeScheduleConfig {

    @Bean(name = "detailFactoryBean")
    public MethodInvokingJobDetailFactoryBean detailFactoryBean(DelListenerPOIScheduler scheduledTasks) {
        MethodInvokingJobDetailFactoryBean bean = new MethodInvokingJobDetailFactoryBean();
        // 這兒設定對應的Job物件
        bean.setTargetObject(scheduledTasks);
        // 這兒設定對應的方法名 與執行具體任務排程類中的方法名對應
        bean.setTargetMethod("doCheck");
        bean.setConcurrent(false);
        return bean;
    }

    @Bean(name = "cronTriggerBean")
    public CronTriggerFactoryBean cronTriggerBean(MethodInvokingJobDetailFactoryBean detailFactoryBean) {
        CronTriggerFactoryBean trigger = new CronTriggerFactoryBean();
        trigger.setJobDetail(detailFactoryBean.getObject());
        try {
            trigger.setCronExpression("0 0 1 * * ?");// 每天1點執行一次
        } catch (Exception e) {
            e.printStackTrace();
        }
        return trigger;

    }

    @Bean
    public SchedulerFactoryBean schedulerFactory(CronTriggerFactoryBean cronTriggerBean) {
        SchedulerFactoryBean schedulerFactory = new SchedulerFactoryBean();
        schedulerFactory.setTriggers(cronTriggerBean.getObject());
        return schedulerFactory;
    }

}
複製程式碼

2), 具體的作業類

複製程式碼
package com.iwhere.easy.travel.timeschedule;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.stereotype.Component;

/**
 * 定時刪除使用者收聽過的poi
 * @author wenbronk
 * @time 2017年3月28日  下午2:01:09  2017
 */
@Component  
@Configurable  
@EnableScheduling
public class DelListenerPOIScheduler {
    private Logger LOGGER = LoggerFactory.getLogger(DelListenerPOIScheduler.class);

    @Autowired
    private StringRedisTemplate redisTemplate;

    public void doCheck() {

        try {
            String key = "noteUserListenedPoi:*";
            redisTemplate.delete(key);
            LOGGER.info("redis中使用者收聽歷史被清空");
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error("redis刪除使用者收聽記錄失敗");
        }
    }

}
複製程式碼