转:java中的定时任务

Posted x-jingxin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了转:java中的定时任务相关的知识,希望对你有一定的参考价值。

引自:http://www.cnblogs.com/wenbronk/p/6433178.html

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删除用户收听记录失败");
        }
    }
    
}

 

系列原创, 转载请注明出处, 谢谢 @Wenbronk: http://www.cnblogs.com/wenbronk/p/6433178.html

以上是关于转:java中的定时任务的主要内容,如果未能解决你的问题,请参考以下文章

Spring 定时任务[转]

(转)Spring定时任务的几种实现

(转) Java中的负数及基本类型的转型详解

转 Spring定时任务的几种实现 (记录备用)

Java 如何实现这样的定时任务

java中的定时器