JavaEE开发之Spring中的多线程编程以及任务定时器详解
上篇博客我们详细的聊了Spring中的事件的发送和监听,也就是常说的广播或者通知一类的东西,详情请移步于《JavaEE开发之Spring中的事件发送与监听以及使用@Profile进行环境切换》。本篇博客我们就聊一下Spring中的并发编程,看一下Spring中的多线程编程和任务的定时执行。下方我们就来聊一下这两方面的内容。
一、Spring中的多线程
本部分就来看一下Spring框架封装下的多线程编程。因为毕竟是被Spring封装过的异步并发编程,所以用起来还是蛮简单的。主要还是ThreadPoolTaskExecutor的使用。下方会给出Spring框架中多线程编程的小示例。
1、创建异步执行任务的Service
下方的AsyncTaskService类就是我们创建的可支持异步任务执行的Service。主要使用了@Async注解来声明方法,使其支持异步任务的执行。在AsyncTaskService方法中,将当前线程的ID进行了打印,以便于我们进行观察。具体如下所示:

2、配置类中的异步设置
我们需要在Spring的配置类中进行异步的相关配置,然后我们使用@Async注解的方法才支持异步执行。下方就是相关的异步配置,首先使用@EnableAsync注解开启异步任务支持,然后实现AsyncConfigurer接口即可。下方TaskExecutorConfig配置类中的两个方法就是AsyncConfigurer接口的方法。
在该接口中,getAsyncExecutor()方法负责提供ThreadPoolTaskExecutor类的对象,在该方法中,我们实例化了ThreadPoolTaskExecutor类对象,然后对其进行了相应的配置。corePoolSize的值说明可开启核心线程数,稍后会进行演示。而maxPoolSize的值是可开启的最大线程数,queueCapacity的属性表示每个线程中可容纳的任务数。
而下方的getAsyncUncaughtExceptionHandler()方法是负责提供异常错误的句柄的。我们可以创建一个继承自ErrorHandler类的错误处理句柄类,在这个类中重写handleUncaughtException()方法,之后在该方法中返回该错误处理句柄的对象即可。当有异常时,会执行我们创建的这个错误句柄中相应的handleUncaughtException()方法。下方我们没有给出错误处理的句柄,直接就返回null即可。

我们可以看一下ThreadPoolTaskExecutor类中的属性,下方是这些属性的默认值了。

3.创建测试的Main方法
下方就是我们创建用来测试的Main方法,其中从Spring容器中获取AsyncTaskService的对象,然后在For循环中调用该对象的异步方法即可。具体代码如下所示:

4.运行结果
我们分别给ThreadPoolTaskExecutor对象的corePoolSize和queueCapacity属性设置相应的值,然后看起运行结果。
(1) corePoolSize = 10 && queueCapacity = 10(并行队列的异步执行)
下方是我们将开启线程数和线程队列容量都设置为10的运行结果。从下方我们可以看出,开启了10个线程,然后进行的异步执行。类似于iOS开发中GCD的并行队列的异步执行方式。

(2) corePoolSize = 1 && queueCapacity = 10(串行队列的异步执行)
接着我们将开启线程的最大值设置为1,然后将每个线程队列的容量设置为10。下方是其运行输出结果,我们可以看出只开启了一个新的线程来顺序执行这for循环中的10次任务都会在这个线程队列中排队执行。这也就是串行队列的异步执行了。

二、任务定时器
接下来我们就来看一下Spring框架中是如何使用@Schedule注解来实现任务定时执行的。@Scheduled注解中,有一些参数,我们可以为这些参数提供不同值来指定不同类型的Schedule。在@Scheduled任务定时器中,我们常用的属性有fixedRate、fixedDelay, cron这三个属性。下方我们将分别讨论着三个属性的具体用法,特别是cron属性,功能是比较强大的。废话少说,进入本部分的主题。
1、开启Schedule支持
首先我们得在Java配置类中开启Schedule的支持,也就是在配置类中添加上@EnableScheduling注解。具体如下所示。配置完后,我们就可以在我们的Service类中使用@Schedule注解来创建定时任务了。

2、创建定时执行的任务测试方法
接下来,我们就来创建Service类中的定时任务执行的测试方法。dateFormat属性负责日期的格式化,sleepTimes数组中的数字则代表每次执行任务所休眠的时间,用来模拟每次任务执行所需要的时间。使用index来标记当前执行的任务次数。
每调用一次testCase()方法,任务就执行一次。testCase()方法中的代码比较简单,在此就不做过多赘述了。

3、fixRate = 3000
fixRate = 3000表示两个相邻任务的开始执行时间的间隔必须大于等于3000毫秒。下方代码片段,是将fixeRate()方法使用@Scheduled声明为定时任务。在fixedRate()方法中调用了this.testCase()方法。在@Scheduled注解中,我们为fixedRate属性指定了一个值为3000ms, 也就是3秒的时间。下方我们会根据运行结果,来看一下fixedRate = 3000的具体作用。

下方截图,就是上述代码运行的测试结果,也就是fixedRate = 3000时的运行结果。然后我们也根据这个结果画出啊了一个任务执行的时间轴。 第一个任务执行开始到结束使用了1秒钟的时间,因为我们设定任务执行的固定频率是3秒,所以下次任务要经过两秒后才能执行。也就是说fixedRate = 3000,意味着从上一个任务执行开始,到下一个任务开始执行的间隔必须大于等于3秒,如果上一个任务的执行时间大于等于3秒的话,那么该任务执行完毕后,就紧接着执行下个任务。

4、fixedDelay = 3000
下方代码段是将fixedDelay属性设置成3000ms,表示在上次任务执行完成之后间隔3秒后在执行下一次任务。

下方就是上述代码所输出的结果,从下方结果中我们不难看出,上个任务结束的时间与下个任务开始的间隔为3秒。具体结果如下所示:

5、cron="0/3 * * * * ?"
cron属性后边紧跟着的是一个表达式,该表达式可表示特定的时间以及某些时间段,当系统时间到达我们设定的时间或者时间段后就会执行我们所指定的任务。在下方代码片段中,我们将cron的值设置为"0/3 * * * * ?"。该表达式的第一个参数就代表着秒,后边的参数表示任意。0/3表示从秒开始每3秒执行一次。

下方就是上述代码的运行结果,从下方结果中我们可以看出,从上一个任务的结束,到下一个任务的开始并不是中间隔着3秒的时间。而是本次任务结束后,如果下次任务开始执行的时间是3秒的倍数,那么下个任务就开始执行。如果不是,就继续等待。所以,我们不难看出下方任务开始的时间都是3的倍数。

6、cron的参数表达式
上一小节只是给出了cron参数的一种形式,接下来我们将详细的看一下cron的参数表达式的构建规则。下方是cron表达式每个位置所表示的时间值,以及取值范围。

秒:表达式的第一位是秒,允许值是0-59,"1,3,5"表示第1、3、5秒执行一次任务,“12-15”相当于12,13,14,15,表示这个范围内的秒数每秒执行一次。“*”就是同配符了,表示任意秒数。“3/5”表示从第三秒开始,每5秒执行一次。(, - * /)
分钟:分钟可支持的表达式形式与秒数一致,可以是“0-59”,“23,45,59”,“3/8”,“*”等格式。(, - * /)
小时:与分钟和秒的差不多,其允许的范围是0-23,可以使用“, - * /”。(, - * /)
日期:日期的范围是1-31,可以表示为“1-5”,“1,4,5”, “*”。“?”表示无意义的值,类似于“*”号。“2/3”,“L”也就是Last的缩写表示该月的最后一天。“W”就是Work的缩写,用法为“18W”表示离18号最近的工作日,比如18号是周日,那么里18号最近的工作日就是下周一了,那也就是19号。如果18号是周六,那么离18号最近的工作日就是本周的周五,也就是17号。如果18号就是周一~周五的某一天,因为18号当天就是工作日,所以“18W”就表示18号就是18号。(? , - * / L W C)
月份:月份的范围是在1~12个月,其中可以使用(, - * /)。
星期:星期的范围是1-7,1表示周日,7表示周六。可以使用(? , - * / L C #)。#号只能在星期中使用,2#3则表示当月第三个个星期的星期一。
年(可选): 范围为1970-2099,可以使用(, - * /)。
看完上面,我们可以给出一个综合的实例,比如“2,6-8 3/5 * LW 3 ? *”则表示离每年的3月份最后一天最近的工作日中每小时的3-5分钟的第2秒以及6~8秒执行一次任务。其实这种表达信息的方式就类似于正则表达式,也就是火星文。cron的用法还是比较灵活的,而且是比较强大的。
本篇博客就先到这儿吧,下篇博客我们会继续聊Spring的相关内容。
github源码分享地址:https://github.com/lizelu/SpringDemo
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco }
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco }
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco }
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco }
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color: #4e9072 }
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color: #4e9072 }
JavaEE开发之Spring中的多线程编程以及任务定时器详解的更多相关文章
- JavaEE开发之Spring中的条件注解组合注解与元注解
上篇博客我们详细的聊了<JavaEE开发之Spring中的多线程编程以及任务定时器详解>,本篇博客我们就来聊聊条件注解@Conditional以及组合条件.条件注解说简单点就是根据特定的条 ...
- JavaEE开发之Spring中的条件注解、组合注解与元注解
上篇博客我们详细的聊了<JavaEE开发之Spring中的多线程编程以及任务定时器详解>,本篇博客我们就来聊聊条件注解@Conditional以及组合条件.条件注解说简单点就是根据特定的条 ...
- JavaEE开发之Spring中Bean的作用域、Init和Destroy方法以及Spring-EL表达式
上篇博客我们聊了<JavaEE开发之Spring中的依赖注入以及AOP>,本篇博客我们就来聊一下Spring框架中的Bean的作用域以及Bean的Init和Destroy方法,然后在聊一下 ...
- JavaEE开发之Spring中的依赖注入与AOP编程
上篇博客我们系统的聊了<JavaEE开发之基于Eclipse的环境搭建以及Maven Web App的创建>,并在之前的博客中我们聊了依赖注入的相关东西,并且使用Objective-C的R ...
- JavaEE开发之Spring中的依赖注入与AOP
上篇博客我们系统的聊了<JavaEE开发之基于Eclipse的环境搭建以及Maven Web App的创建>,并在之前的博客中我们聊了依赖注入的相关东西,并且使用Objective-C的R ...
- JavaEE开发之Spring中的事件发送与监听以及使用@Profile进行环境切换
本篇博客我们就来聊一下Spring框架中的观察者模式的应用,即事件的发送与监听机制.之前我们已经剖析过观察者模式的具体实现,以及使用Swift3.0自定义过通知机制.所以本篇博客对于事件发送与监听的底 ...
- JavaEE开发之SpringMVC中的自定义拦截器及异常处理
上篇博客我们聊了<JavaEE开发之SpringMVC中的路由配置及参数传递详解>,本篇博客我们就聊一下自定义拦截器的实现.以及使用ModelAndView对象将Controller的值加 ...
- JavaEE开发之SpringMVC中的静态资源映射及服务器推送技术
在上篇博客中,我们聊了<JavaEE开发之SpringMVC中的自定义拦截器及异常处理>.本篇博客我们继续的来聊SpringMVC的东西,下方我们将会聊到js.css这些静态文件的加载配置 ...
- JavaEE开发之SpringMVC中的自定义消息转换器与文件上传
上篇博客我们详细的聊了<JavaEE开发之SpringMVC中的静态资源映射及服务器推送技术>,本篇博客依然是JavaEE开发中的内容,我们就来聊一下SpringMVC中的自定义消息转发器 ...
随机推荐
- [java多线程] - 锁机制&同步代码块&信号量
在美眉图片下载demo中,我们可以看到多个线程在公用一些变量,这个时候难免会发生冲突.冲突并不可怕,可怕的是当多线程的情况下,你没法控制冲突.按照我的理解在java中实现同步的方式分为三种,分别是:同 ...
- BZOJ 1095: [ZJOI2007]Hide 捉迷藏(线段树维护括号序列)
这个嘛= =链剖貌似可行,不过好像代码长度很长,懒得打(其实是自己太弱了QAQ)百度了一下才知道有一种高大上的叫括号序列的东西= = 岛娘真是太厉害了,先丢链接:http://www.shuizilo ...
- 本地Solr服务器搭建
一.Solr官网下载http://lucene.apache.org/solr/下载Solr项目文件 在该项目文件中,可以找到我们在本地环境下运行Solr服务器所需要的资源文件,在这里我们以4.10. ...
- webpack(四)处理 css\less\sass 样式
(一) 处理普通的.css 文件,需要安装 css-loader,style-loader .less 文件,需要安装 less-loader .sass 文件,需安装 less-loader np ...
- HTML入门
一些说明 写在前面:HTML和CSS,当你了解所有规则后,你应该多写页面并记录你出现的问题,这才是学习HTML和CSS的最佳方法 这是我学习一段时间之后,再次回顾HTML,希望大家也对HTML有不一样 ...
- 2017,科学使用strace神器(附代码,举栗子)
我感到惊讶,都2017年了,几乎没有人知道他们可以使用strace的了解所有事情.它总是我拔出的第一个调试工具之一,因为它通常在我运行的Linux系统上可用,并且它可以用于解决各种各样的问题. 什么是 ...
- CDIF: 基于JSON的SOA软件框架
通用设备互联框架(CDIF)是一个具备中美知识产权保护的,基于web的连接框架,目前有部分开源实现存放在: GitHub - out4b/cdif: Common device interconnec ...
- KoaHub.js -- 基于 Koa.js 平台的 Node.js web 快速开发框架之koahub-skip
koahub-skip koahub skip middleware koahub skip Conditionally skip a middleware when a condition is m ...
- git remote log error
使用git pull的时候收到以下信息: error: there are still refs under 'refs/remotes/origin/xxxx'From 10.1.25.57:yyy ...
- javascript 随机显示指定内容
今天碰到一个需求,一个页面显示赞助厂商的信息,但是厂商要求排序要随机排,因为是个静态页面不是读取数据库的,所以打算用js来控制 var arr = new Array('张三', '李四', '王五' ...