Java web项目创建笔记19 之《spring定时任务功能(2)》

一、使用task命名空间
以下均在spring-job.xml中添加
1、创建一个ThreadPoolTaskScheduler实例

<task:scheduler id="threadPoolTaskScheduler" pool-size="5"/>

相当于:

	<bean id="threadPoolTaskScheduler"
		class="org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler">
		<property name="poolSize" value="5" />
	</bean>

2、创建一个ThreadPoolTaskExecutor实例

<task:executor id="executor"
		 pool-size="5-10"
		 queue-capacity="25"
		 rejection-policy="ABORT"/>

相当于:

	<bean id="threadPoolTaskExecutor"
		class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
		<!-- 核心线程数 -->
		<property name="corePoolSize" value="5" />
		<!-- 最大线程数 -->
		<property name="maxPoolSize" value="10" />
		<!-- 队列最大长度 -->
		<property name="queueCapacity" value="25" />
	</bean>

3、rejection-policy定义了拒绝策略
当最大线程数满了,等待队列也满了的时候,有新任务需要执行时会触发拒绝策略,有4种情况:
1)AbortPolicy:对拒绝任务抛弃处理,并且抛出TaskRejectedException异常
配置项:ABORT(缺省)
2)DiscardPolicy:对拒绝任务抛弃处理,并且没有异常抛出
配置项:DISCARD
3)DiscardOldestPolicy:抛弃队列里面等待最久的一个线程(队列最前面的任务),然后把拒绝任务加到队列
配置项:DISCARD_OLDEST
4)CallerRunsPolicy:不在新线程中执行任务,而是有调用者所在的线程来执行
配置项:CALLER_RUNS(不建议使用)

二、使用注解方式
1、使用@Async和@Scheduled注解
打开注解驱动,可以使用@Async和@Scheduled注解

<task:annotation-driven />

2、@Async注解
可以加在方法上:表示这个方法是异步执行的
也可以加在类上:表示这个类中的所有方法都是异步执行的
该注解仅仅表示方法是异步执行的,此时你还需要配置一个线程池
1)在com.study.schedule包下添加AsyncTask.java

package com.study.schedule;

import java.util.Random;

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

@Component
public class AsyncTask {

	@Async
	public void start(int num) throws Exception {
		Random r = new Random();
		System.out.println("" + num + "号马起跑了...");
		Thread.sleep(r.nextInt(1000));
		System.out.println("" + num + "号马已经跑完了");
	}
}

2)添加测试方法asyncTaskTest

	@Autowired
	AsyncTask asyncTask;

	...

	@Test
	public void asyncTaskTest() throws Exception {
		asyncTask.start(1);
		asyncTask.start(2);
		asyncTask.start(3);
		asyncTask.start(4);
		asyncTask.start(5);
		asyncTask.start(6);
	}

3)测试方法执行结果

测试开始----------
测试结束----------
1号马起跑了...
6号马起跑了...
2号马起跑了...
4号马起跑了...
5号马起跑了...
3号马起跑了...
6号马已经跑完了
5号马已经跑完了
2号马已经跑完了
3号马已经跑完了
1号马已经跑完了
4号马已经跑完了

任务线程是异步执行的

3、@Scheduled注解
在不配置ThreadPoolTaskExecutor和ThreadPoolTaskScheduler的情况下,@scheduled注解配置的任务默认是单线程执行
1)在com.study.schedule包下添加ScheduledTask.java

package com.study.schedule;

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class ScheduledTask {

	@Scheduled(cron = "*/10 * * * * ?")
	public void start() throws Exception {
		System.out.println("ScheduledTask1任务启动了...");
		Thread.sleep(10000);
	}
	
	@Scheduled(cron = "*/1 * * * * ?")
	public void start2() throws Exception {
		System.out.println("ScheduledTask2任务启动了...");
	}
}

定义了两个任务,任务1:10秒钟执行一次,且线程睡眠10秒,任务2:1秒钟执行一次,线程不睡眠
2)添加测试方法schdeuledTaskTest

	@Test
	public void schdeuledTaskTest() throws Exception {
		System.out.println("hello world");
		Thread.sleep(30000);
	}

主线程执行后会睡眠30秒
3)测试方法执行结果

测试开始----------
hello world
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask1任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask1任务启动了...
测试结束----------

可以看到Task2任务,在主线程执行过程中,共执行了14次,其余时间由Task1任务占用,所以是@Scheduled默认是同步执行的
4)@Scheduled配合<task:scheduler id="threadPoolTaskScheduler" pool-size="5"/>,即创建ThreadPoolTaskScheduler对象
测试方法执行结果

测试开始----------
hello world
ScheduledTask1任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask1任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
测试结束----------

Task1执行后,Task2执行了20次后,Task1再次执行,所以线程是异步执行的

4、scheduled-tasks标签
以xml方式定义定时任务,效果等同于@Scheduled注解
1)spring-job.xml添加

	<task:scheduled-tasks>
		<task:scheduled ref="taskJobs" method="job1" initial-delay="5000" fixed-rate="5000"/>
		<task:scheduled ref="taskJobs" method="job2" cron="*/10 * * * * ?"/>
	</task:scheduled-tasks>

定义了两个任务,任务1:延迟加载5秒钟,每5秒钟一次,任务2:每10秒钟执行一次
2)在com.study.schedule包添加TaskJobs.java

package com.study.schedule;

import org.springframework.stereotype.Component;

@Component
public class TaskJobs {
	
	public void job1() {
		System.out.println("job1 start...");
	}
	
	public void job2() {
		System.out.println("job2 start...");
	}
	
	public void job3() {
		System.out.println("job3 start...");
	}
}

3)执行测试方法schdeuledTaskTest

测试开始----------
hello world
job2 start...
ScheduledTask2任务启动了...
ScheduledTask1任务启动了...
ScheduledTask2任务启动了...
job1 start...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
job1 start...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
job2 start...
ScheduledTask2任务启动了...
job1 start...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
job1 start...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
job2 start...
ScheduledTask2任务启动了...
ScheduledTask1任务启动了...
ScheduledTask2任务启动了...
job1 start...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
job1 start...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
ScheduledTask2任务启动了...
测试结束----------

在30秒内,job1执行了6次,job2执行了3次,和定义的间隔时间一致
4)task:scheduled标签参数
ref:引用的类
method:类中的方法
initial-delay:首次调用前的延迟时间
fixed-delay:上一次调用结束,下一次调用开始的延迟时间
fixed-rate:距上一次调用开始时间后的间隔时间(不用等待上一次调用完成,有并发问题)
cron:cron表达式

三、小结
1、@Async注解,默认情况下用的是SimpleAsyncTaskExecutor线程池,不是真正意义上的线程池,因为线程不重用,每次调用都会创建一个新的线程,每次打印的线程名称是[task-1]、[task-2]、[task-3]...依次递增
2、SyncTaskExecutor:没有实现异步调用,只是一个同步操作
3、ConcurrentTaskExecutor:Executor的适配类,不推荐使用。如果ThreadPoolTaskExecutor不满足要求时,才考虑使用这个类
4、ThreadPoolTaskScheduler:可以使用cron表达式
5、ThreadPoolTaskExecutor:最常使用,推荐,其是对ThreadPoolExecutor的包装

四、参考资料
https://blog.csdn.net/xueyunzi1/article/details/89632988

注:最新代码上传至https://github.com/csj50/webapp2.git
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值