1.功能说明

Spring提供了Async注解来实现方法的异步调用。

即当调用Async标识的方法时,调用线程不会等待被调用方法执行完成即返回继续执行以下操作,而被调用的方法则会启动一个独立线程来执行此方法

这种异步执行的方式通常用于处理接口中不需要返回给用户的数据处理。比如当注册的时候,只需要将用户信息返回用户,而关于信息的保存操作可以使用异步执行。

Spring提供了Scheduled注解来实现定时任务的功能。

在异步方法和定时任务功能中都是开发这自己定义需要执行的方法,然后交给Spring容器管理线程,并执行相应的方法。在使用异步方法和定时任务的时候需要特别注意的是线程池的配置以及任务中异常的处理。下面对这两个功能进行简单介绍。

2.关键注解和配置接口

功能开启注解:

EnableAsync和EnableScheduling

通过在Spring的配置类中添加这两个注解来开启Spring的异步方法和定时任务的功能

异步方法标识注解Async,其定义为:

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Async { String value() default ""; }

在注解定义中可以看到此注解可以用于type和method,当此注解用于类的时候,表示此类中的所有方法都为异步方法。此注解中的value属性可用于指定执行此异步方法的线程池。线程池的具体确定方法下面具体分析。

定时任务标识注解Scheduled,定义如下:

@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repeatable(Schedules.class)
public @interface Scheduled {
定时任务
String cron() default ""; String zone() default "";
//上次执行结束到下次执行开始
long fixedDelay() default -1; String fixedDelayString() default "";
上次执行开始到本次执行开始
long fixedRate() default -1; fixedRate或者fixedDelay的时候第一次的延迟时间
long initialDelay() default -1; }

3.Spring线程池的选择和自定义配置线程池

在项目中我们通常不会自己手动创建线程,而是通过统一的线程池来执行task或者异步方法,使用这种方法来避免多人团队中由于自定义线程导致的资源耗尽的问题。在自定义线程池之前首先要了解Spring在执行异步任务或者方法的时候是怎么选择线程池的。

3.1 Async对于线程池的选择顺序

Async线程池的选择顺序如下图所示:

Spring在执行async标识的异步方法的时候首先会在Spring的上下文中搜索类型为TaskExecutor或者名称为“taskExecutor”的bean,当可以找到的时候,就将任务提交到此线程池中执行。当不存在以上线程池的时候,Spring会手动创建一个SimpleAsyncTaskExecutor执行异步任务。

另外当标识async注解的时候指定了,value值,Spring会使用指定的线程池执行。比如以下:

@Async(value = "asyncTaskThreadPool")

这个时候Spring会去上下文中找名字为asyncTaskThreadPool的bean,并执行异步任务,找不到,会抛出异常。

3.2 Scheduled对于线程池的选择顺序

Scheduled对于线程池的选择顺序如下图所示:

当Spring执行定时任务的时候,首先会在上下文中找类型为TaskScheduler或者名称为taskScheduler的bean,找不到的时候会手动创建一个线程执行此task。

3.3 自定义线程池和异常处理

在了解了Spring对于线程池的选择后,我们需要自定义线程池。自定义Async线程池有三种方式。

方法一:首先配置接口,重写获取线程池的方法。

配置Async方法的线程池需要继承AsyncConfigurerSupport类,或者实现AsyncConfigurer接口,并重写getAsyncExecutor方法,代码如下:

@Configuration
@EnableAsync
public class ThreadPoolBeanFactory extends AsyncConfigurerSupport{ @Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor asyncTaskThreadPool = new ThreadPoolTaskExecutor();
asyncTaskThreadPool.setCorePoolSize(100);
asyncTaskThreadPool.setMaxPoolSize(200);
asyncTaskThreadPool.setQueueCapacity(11);
asyncTaskThreadPool.setThreadFactory(new ThreadFactory() { private final AtomicLong index = new AtomicLong(1);
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "Async-override-task-pool-thread-" + index.getAndIncrement());
}
});
asyncTaskThreadPool.initialize();
return asyncTaskThreadPool;
} @Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
//返回值为void的异步方法不会传递异常,当方法中出现异常的时候只会打印日志,重写此方法来自定义异常处理方法
return null;
}
}

这种定义的方法缺点是没有定义bean。

方法二:自定义相应类型的线程池bean。

第二种方法是基于Spring对线程选择的原理来实现的,定义一个类型为TaskExecutor的bean,定义方式如下:

    @Bean
public TaskExecutor asyncTaskThreadPool() { ThreadPoolTaskExecutor asyncTaskThreadPool = new ThreadPoolTaskExecutor();
asyncTaskThreadPool.setCorePoolSize(100);
asyncTaskThreadPool.setMaxPoolSize(200);
asyncTaskThreadPool.setThreadFactory(new ThreadFactory() { private final AtomicLong index = new AtomicLong(1);
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "Async-task-pool-thread-" + index.getAndIncrement());
}
});
// asyncTaskThreadPool.initialize();//当为bean的时候不需要调用此方法,装载容器的时候回自动调用
return asyncTaskThreadPool;
}

以上两种方式定义线程池的时候在定义异步方法可以不执行线程池。定义如下:

    @Async
public void test(){
System.out.println(Thread.currentThread().getName()); }

此时Spring会自动使用以上定义的线程池执行此方法。使用以上两种配置输出结果依次是:

Async-task-pool-thread-1
Async-task-override-pool-thread-1

方法三 在Async注解中执行线程池名称

异步任务定义如下:

    @Async(value = "asyncTaskThreadPool")
public void asyncTask2() {
LOGGER.info("AsyncTask2 start.");
LOGGER.info(Thread.currentThread().getName());
LOGGER.info("AsyncTask2 finished.");
}

此时Spring会在上下文中找名称为asyncTaskThreadPool的线程池来执行此任务。

类似的可以自定义Scheduled的线程池,需要实现的配置接口为:SchedulingConfigurer。方法类似。

4.Async返回操作结果

异步任务可以通过定义返回类型为Future来实现返回值,定义如下:

    @Async
public Future<String> asyncTaskWithResult() {
LOGGER.info("AsyncTaskWithResult start.");
try {
Thread.sleep(1000 * 10);
} catch (Exception e) {
return new AsyncResult<>("error" + e.getMessage());
}
LOGGER.info("AsyncTaskWithResult finished."); return new AsyncResult<>("success");
}

5.编写单元测试测试功能

单元测试代码如下:

@RunWith(SpringRunner.class)
@SpringBootTest
public class AsyncApplicationTests { @Autowired
private AsyncTaskService asyncTaskService; @Test
public void asyncTest() throws Exception{
Future<String> future = asyncTaskService.asyncTaskWithResult(); while (!future.isDone()) {
System.out.println("Wait asyncTaskWithResult.");
Thread.sleep(1000);
}
System.out.println("asyncTaskWithResult result is:" + future.get());
System.out.println("asyncTask finished."); } }

输出内容如下:

Wait asyncTaskWithResult.
Wait asyncTaskWithResult.
Wait asyncTaskWithResult.
Wait asyncTaskWithResult.
Wait asyncTaskWithResult.
Wait asyncTaskWithResult.
Wait asyncTaskWithResult.
Wait asyncTaskWithResult.
Wait asyncTaskWithResult.
Wait asyncTaskWithResult.
AsyncTaskWithResult finished.
asyncTaskWithResult result is:success
asyncTask finished.

SpringBoot中Async异步方法和定时任务介绍的更多相关文章

  1. 定时任务-----Springboot中使用Scheduled做定时任务----http://www.cnblogs.com/lirenqing/p/6596557.html

    Springboot中使用Scheduled做定时任务---http://www.cnblogs.com/lirenqing/p/6596557.html 已经验证的方案: pom文件加入依赖 < ...

  2. SpringBoot中使用@Scheduled创建定时任务

    SpringBoot中使用@Scheduled创建定时任务 定时任务一般会在很多项目中都会用到,我们往往会间隔性的的去完成某些特定任务来减少服务器和数据库的压力.比较常见的就是金融服务系统推送回调,一 ...

  3. SpringBoot中使用Scheduling执行定时任务

    SpringBoot自带的 Schedule,可以将它看成一个轻量级的Quartz,而且使用起来比Quartz简单许多 以下任务都是在单线程下执行的 第一步 创建SpringBoot项目 第二步 外汇 ...

  4. SpringBoot中使用task实现定时任务

    定时任务实现的几种方式: Timer:这是java自带的java.util.Timer类,这个类允许你调度一个java.util.TimerTask任务.使用这种方式可以让你的程序按照某一个频度执行, ...

  5. Springboot中使用Scheduled做定时任务

    在开发中,定时任务是常见的功能,在spring boot 下开发定时任务其实很简单,具体代码如下: 1.配置依赖包pom.xml 由于默认的maven仓库经常访问不了,这里采用了阿里云的maven仓库 ...

  6. Springboot中定时任务的使用

    在springboot中已经集成了定时任务,只需要在启动类上加注解@EnableScheduling即可 例如: 添加类加上@Component注解,添加方法加上@Scheduler即可

  7. SpringBoot中并发定时任务的实现、动态定时任务的实现(看这一篇就够了)

    原创不易,如需转载,请注明出处https://www.cnblogs.com/baixianlong/p/10659045.html,否则将追究法律责任!!! 一.在JAVA开发领域,目前可以通过以下 ...

  8. 在SpringBoot中配置定时任务

    前言 之前在spring中使用过定时任务,使用注解的方式配置很方便,在SpringBoot中的配置基本相同,只是原来在spring中的xml文件的一些配置需要改变,在SpringBoot中也非常简单. ...

  9. SpringBoot 中常用注解@PathVaribale/@RequestParam/@GetMapping介绍

    SpringBoot 中常用注解@PathVaribale/@RequestParam/@GetMapping介绍 本篇博文将介绍几种如何处理url中的参数的注解@PathVaribale/@Requ ...

随机推荐

  1. 【转发活动】Hey, 是你吗? | 寻"粉"启示

    你知道吗 从 A computer on every desk and in every home 让每张办公桌上和每个家庭都有一台计算机 ▼ 到 Where do you want to go to ...

  2. Element-ui多选下拉实现全部与其他互斥

    1.以事件类型为例,给下拉绑定选项改变的change事件 2.当已选项个数大于1(即先选了其他,再选不限)且最后选的是不限时,取消其他选项选中状态: 当已选项个数等于2(即先选了不限,再选其他)且第一 ...

  3. cms-详细页面-3

    1.设置上一条.下一条数据 2.使用昌言插件 3.点击链接帖子的访问数加一 1.在mapper中设置分页: <?xml version="1.0" encoding=&quo ...

  4. HDU 1009 FatMouse' Trade肥老鼠的交易(AC代码) 贪心法

    题意: 一只老鼠用猫粮来换豆子,每个房间的兑换率不同,所以得尽量从兑换率高的房间先兑换.肥老鼠准备M磅猫粮去跟猫交易,让猫在warehouse中帮他指路,以找到好吃的.warehouse有N个房间,第 ...

  5. jquery实现加载更多效果

    情况是当滑动条滑动到最底部的时候,数据显示出一部分的更多 思路:获取到浏览器屏幕的高度client,文档的高度h和滑动距离顶部的距离scroll,当h<=client+scroll的时候就是滑动 ...

  6. linux 命令——21 find(转)

    在 使用 find命令的-exec选项处理匹配到的文件时, find命令将所有匹配到的文件一起传递给exec执行.但有些系统对能够传递给exec的命 令长度有限制,这样在find命令运行几分钟之后,就 ...

  7. POJ-3436 ACM Computer Factory---最大流+拆点

    题目链接: https://vjudge.net/problem/POJ-3436 题目大意: 每台电脑有p个组成部分,有n个工厂加工电脑.每个工厂对于进入工厂的半成品的每个组成部分都有要求,由p个数 ...

  8. [OS] 可执行文件的装载

    http://www.jianshu.com/p/e1300e7a4c48 1. 虚拟内存 在早期的计算机中,程序是直接运行在物理内存上的,程序在运行时访问的地址就是物理地址.可是,当计算机中同时运行 ...

  9. opencv approxPolyDP使用

    代码: import cv2 import numpy as np # img = cv2.imread('/home/sensetime/edgeBoxes-Cpp-version/output/i ...

  10. eclipse中的字体大小设置和背景色设置

    1.字体大小设置 在basic下选择最后一个TextFont 护眼背景色设置 添加到自定义颜色后点确定 最后一步点apply