java实现定时任务 schedule_Java 定时任务的几种实现方式

JAVA实现定时任务的几种方式

@(JAVA)[spring|quartz|定时器]

近期项目开发中需要动态的添加定时任务,比如在某个活动结束时,自动生成获奖名单,导出excel等,此类任务由于活动时间是动态的,不能把定时任务配置在配置文件或写死在代码中。当然也可以增加一个定时扫描的任务来实现。借此机会整理了AVA实现定时任务的几种常用方式,以下做简要介绍。

目前主要有以下几种实现方式:

- JDK自带 :JDK自带的Timer以及JDK1.5+ 新增的ScheduledExecutorService;

- Quartz :简单却强大的JAVA作业调度框架

- Spring3.0以后自带的task :可以将它看成一个轻量级的Quartz,而且使用起来比Quartz简单许多;

下面将一一介绍以上三种实现方式。

JDK 自带的定时器实现

Timer类

这个类允许你调度一个java.util.TimerTask任务。主要有以下几个方法:

1. schedule(TimerTask task, long delay) 延迟 delay 毫秒 执行

public static void main(String[] args) {

for (int i = 0; i < 10; ++i) {

new Timer("timer - " + i).schedule(new TimerTask() {

@Override

public void run() {

println(Thread.currentThread().getName() + " run ");

}

}, 1000);

}

}

out :

timer - 2 run

timer - 1 run

timer - 0 run

timer - 3 run

timer - 9 run

timer - 4 run

timer - 8 run

timer - 5 run

timer - 6 run

timer - 7 run

2. schedule(TimerTask task, Date time) 特定時間執行

public static void main(String[] args) {

for (int i = 0; i < 10; ++i) {

new Timer("timer - " + i).schedule(new TimerTask() {

@Override

public void run() {

println(Thread.currentThread().getName() + " run ");

}

}, new Date(System.currentTimeMillis() + 2000));

}

}

out:

timer - 0 run

timer - 7 run

timer - 6 run

timer - 8 run

timer - 3 run

timer - 5 run

timer - 2 run

timer - 1 run

timer - 4 run

timer - 9 run

3. schedule(TimerTask task, long delay, long period) 延迟 delay 执行并每隔period 执行一次

public static void main(String[] args) {

for (int i = 0; i < 10; ++i) {

new Timer("timer - " + i).schedule(new TimerTask() {

@Override

public void run() {

println(Thread.currentThread().getName() + " run ");

}

}, 2000 , 3000);

}

}

out:

timer - 0 run

timer - 5 run

timer - 4 run

timer - 8 run

timer - 3 run

timer - 2 run

timer - 1 run

timer - 7 run

timer - 9 run

timer - 6 run

timer - 3 run

timer - 7 run

timer - 5 run

timer - 4 run

timer - 8 run

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

ScheduledExecutorService 接口实现类

ScheduledExecutorService 是JAVA 1.5 后新增的定时任务接口,主要有以下几个方法。

- ScheduledFuture> schedule(Runnable command,long delay, TimeUnit unit);

- ScheduledFuture schedule(Callable callable,long delay, TimeUnit unit);

- ScheduledFuture> scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnitunit);

- ScheduledFuture> scheduleWithFixedDelay(Runnable command,long initialDelay,long delay,TimeUnitunit);

1

2

3

4

默认实现为ScheduledThreadPoolExecutor 继承了ThreadPoolExecutor 的线程池特性,配合future特性,比Timer更强大。 具体用法可以阅读JDK文档;spring Task内部也是依靠它实现的。示例代码:

public static void main(String[] args) throws SchedulerException {

ScheduledThreadPoolExecutor executor = (ScheduledThreadPoolExecutor)Executors.newScheduledThreadPool(10);

for (int i = 0; i < 10; ++i) {

executor.schedule(new Runnable() {

@Override

public void run() {

System.out.println(Thread.currentThread().getName() + " run ");

}

} , 2 , TimeUnit.SECONDS);

}

executor.shutdown();

}

out:

pool-1-thread-2 run

pool-1-thread-5 run

pool-1-thread-4 run

pool-1-thread-3 run

pool-1-thread-8 run

pool-1-thread-5 run

pool-1-thread-7 run

pool-1-thread-2 run

pool-1-thread-1 run

pool-1-thread-6 run

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

Quartz 定时器实现

Quartz是一个完全由Java编写的开源作业调度框架,为在Java应用程序中进行作业调度提供了简单却强大的机制。Quartz允许开发人员根据时间间隔来调度作业。它实现了作业和触发器的多对多的关系,还能把多个作业与不同的触发器关联。可以动态的添加删除定时任务,另外很好的支撑集群调度。简单地创建一个org.quarz.Job接口的Java类,Job接口包含唯一的方法:

public void execute(JobExecutionContext context) throws JobExecutionException;

1

2

在Job接口实现类里面,添加需要的逻辑到execute()方法中。配置好Job实现类并设定好调度时间表(Trigger),Quartz就会自动在设定的时间调度作业执行execute()。

整合了Quartz的应用程序可以重用不同事件的作业,还可以为一个事件组合多个作业。Quartz通过属性文件来配置JDBC事务的数据源、全局作业、触发器侦听器、插件、线程池等等。(quartz.properties)

通过maven引入依赖(这里主要介绍2.3.0) 注意:shiro-scheduler中依赖的是1.x版本 如果同时使用会冲突

org.quartz-scheduler

quartz

2.3.0

1

2

3

4

5

6

创建Job类

public class TestJob implements Job{

@Override

public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {

println(Thread.currentThread().getName() + " test job begin " + DateUtil.getCurrentTimeStr());

}

}

1

2

3

4

5

6

调度任务

public static void main(String[] args) throws InterruptedException, SchedulerException {

Scheduler scheduler = new StdSchedulerFactory().getScheduler();

// 开始

scheduler.start();

// job 唯一标识 test.test-1

JobKey jobKey = new JobKey("test" , "test-1");

JobDetail jobDetail = JobBuilder.newJob(TestJob.class).withIdentity(jobKey).build();

Trigger trigger = TriggerBuilder.newTrigger()

.withIdentity("test" , "test")

// 延迟一秒执行

.startAt(new Date(System.currentTimeMillis() + 1000))

// 每隔一秒执行 并一直重复

.withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(1).repeatForever())

.build();

scheduler.scheduleJob(jobDetail , trigger);

Thread.sleep(5000);

// 删除job

scheduler.deleteJob(jobKey);

}

out :

DefaultQuartzScheduler_Worker-1test job begin 2017-06-03 14:30:33

DefaultQuartzScheduler_Worker-2test job begin 2017-06-03 14:30:34

DefaultQuartzScheduler_Worker-3test job begin 2017-06-03 14:30:35

DefaultQuartzScheduler_Worker-4test job begin 2017-06-03 14:30:36

DefaultQuartzScheduler_Worker-5test job begin 2017-06-03 14:30:37

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

Quartz 主要包含以下几个部分

Job:是一个接口,只有一个方法void execute(JobExecutionContext

context),开发者实现该接口定义运行任务,JobExecutionContext类提供了调度上下文的各种信息。Job运行时的信息保存在JobDataMap实例中;

JobDetail:Quartz在每次执行Job时,都重新创建一个Job实例,所以它不直接接受一个Job的实例,相反它接收一个Job实现类,以便运行时通过newInstance()的反射机制实例化Job。因此需要通过一个类来描述Job的实现类及其它相关的静态信息,如Job名字、描述、关联监听器等信息,JobDetail承担了这一角色。

Trigger:是一个类,描述触发Job执行的时间触发规则。主要有SimpleTrigger和CronTrigger这两个子类。当仅需触发一次或者以固定时间间隔周期执行,SimpleTrigger是最适合的选择;而CronTrigger则可以通过Cron表达式定义出各种复杂时间规则的调度方案:如每早晨9:00执行,周一、周三、周五下午5:00执行等;

Calendar:org.quartz.Calendar和java.util.Calendar不同,它是一些日历特定时间点的集合(可以简单地将org.quartz.Calendar看作java.util.Calendar的集合——java.util.Calendar代表一个日历时间点,无特殊说明后面的Calendar即指org.quartz.Calendar)。一个Trigger可以和多个Calendar关联,以便排除或包含某些时间点。假设,我们安排每周星期一早上10:00执行任务,但是如果碰到法定的节日,任务则不执行,这时就需要在Trigger触发机制的基础上使用Calendar进行定点排除。

Scheduler:代表一个Quartz的独立运行容器,Trigger和JobDetail可以注册到Scheduler中,两者在Scheduler中拥有各自的组及名称,组及名称是Scheduler查找定位容器中某一对象的依据,Trigger的组及名称必须唯一,JobDetail的组和名称也必须唯一(但可以和Trigger的组和名称相同,因为它们是不同类型的)。Scheduler定义了多个接口方法,允许外部通过组及名称访问和控制容器中Trigger和JobDetail。

Scheduler可以将Trigger绑定到某一JobDetail中,这样当Trigger触发时,对应的Job就被执行。一个Job可以对应多个Trigger,但一个Trigger只能对应一个Job。可以通过SchedulerFactory创建一个Scheduler实例。Scheduler拥有一个SchedulerContext,它类似于ServletContext,保存着Scheduler上下文信息,Job和Trigger都可以访问SchedulerContext内的信息。SchedulerContext内部通过一个Map,以键值对的方式维护这些上下文数据,SchedulerContext为保存和获取数据提供了多个put()和getXxx()的方法。可以通过Scheduler#

getContext()获取对应的SchedulerContext实例;

ThreadPool:Scheduler使用一个线程池作为任务运行的基础设施,任务通过共享线程池中的线程提高运行效率。

关于简单使用,可以参考quartz的example,下面链接是一些入门帮助。

深入学习可以阅读官方文档和相关博客阅读

以下为推荐博客地址

quartz详解2:quartz由浅入深

Spring 相关的任务调度

Spring 3.0+ 自带的任务调度实现,主要依靠TaskScheduler接口的几个实现类实现。删除和修改任务比较麻烦。

主要用法有以下三种:

Spring配置文件实现

注解实现

代码动态添加

配置文件实现

spring-schedule.xml

1

2

3

4

5

6

注解实现

spring-schedule.xml

// 启用注解

1

2

3

4

@Component

public class Task{

@Scheduled(cron="0/5 * * * * ? ") //每5秒执行一次

public void execute(){

DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

System.out.println(sdf.format(DateTime.now().toDate())+"*********B任务每5秒执行一次进入测试");

}

}

1

2

3

4

5

6

7

8

9

代码动态添加

spring-schedule.xml

1

2

3

4

5

6

7

8

@Component

public class Test {

@Autowired

private ThreadPoolTaskScheduler myScheduler;

public void addJob(){

myScheduler.schedule(new Runnable() {

@Override

public void run() {

System.out.println(Thread.currentThread().getName() + " run ");

}

} , new CronTrigger("0/5 * * * * ? ")); //每5秒执行一次

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

spring 结合 quartz 实现任务调度

spring 配置文件 spring-quartz.xml

com.test.TestJob

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

动态增加删除

@Component

public class Test {

@Autowired

private SchedulerFactoryBean quartzScheduler;

public void addJob() throws SchedulerException {

Scheduler scheduler = quartzScheduler.getScheduler();

JobKey jobKey = new JobKey("test", "test");

if (scheduler.checkExists(jobKey)) {

return;

}

JobDetail jobDetail = JobBuilder.newJob(TestJob.class).withIdentity(jobKey).build();

Trigger trigger = TriggerBuilder.newTrigger().withIdentity("test", "test")

.withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(1).repeatForever()).build();

scheduler.scheduleJob(jobDetail, trigger);

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

以上仅仅是对自己学习的总结,深入了解还需查找相关资料。比如动态增加,修改定时任务。以及Quartz的集群模式等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值