SpringBoot实现定时任务和异步调用

 更新时间:2019年04月26日 11:17:10   作者:叶落自飘零   我要评论
这篇文章主要为大家详细介绍了SpringBoot实现定时任务和异步调用,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

本文实例为大家分享了SpringBoot实现定时任务和异步调用的具体代码,供大家参考,具体内容如下

环境:

jdk1.8;spring boot2.0.2;Maven3.3

摘要说明:

定时任务:定时任务是业务场景中经常出现的一种情况如:定时发送邮件,短信、定时监控数据、定时对账等

异步调用:一个都买流程可能包括下单、发货通知、短信推送、消息推送等,其实除了下单这个主要程序是主程序,其他子程序可以同时进行且不影响主程序的运行,这个时候就可以使用异步调用来调用这些子程序;

步骤:

1.定时任务

a.在spring boot主类上使用注解@EnableScheduling启动定时任务:

package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
//启动定时任务
@EnableScheduling
@SpringBootApplication
public class DemoApplication {
 public static void main(String[] args) {
 SpringApplication.run(DemoApplication.class, args);
 }
}

b.实现定时任务(使用@Component注解来标注组件)

 /**
 * @模块名:demo
 * @包名:com.example.demo.test1.component
 * @描述:SchedulingComponent.java
 * @版本:1.0
 * @创建人:cc
 * @创建时间:2018年9月29日上午10:19:37
 */
package com.example.demo.test1.component;
import java.util.Date;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
/**
 * @模块名:demo
 * @包名:com.example.demo.test1.component @类名称: SchedulingComponent
 * @类描述:【类描述】用于测试定时任务 @版本:1.0
 * @创建人:cc
 * @创建时间:2018年9月29日上午10:19:37
 */
@Component
public class SchedulingComponent {
 /**
 * 
 * @方法名:testScheduling1
 * @方法描述【方法功能描述】测试定时任务,没三秒执行一次
 * @修改描述【修改描述】
 * @版本:1.0
 * @创建人:cc
 * @创建时间:2018年9月29日 上午10:26:20
 * @修改人:cc
 * @修改时间:2018年9月29日 上午10:26:20
 */
 @Scheduled(fixedRate = 3000)
 public void testScheduling1() {
 System.out.println("执行时间为"+new Date()+"执行testScheduling1");
 }
}
@Scheduled注解和之前spring使用xml配置定时任务类似:
@Scheduled(fixedRate = 5000) :上一次开始执行时间点之后5秒再执行
@Scheduled(fixedDelay = 5000) :上一次执行完毕时间点之后5秒再执行
@Scheduled(initialDelay=1000, fixedRate=5000) :第一次延迟1秒后执行,之后按fixedRate的规则每5秒执行一次
@Scheduled(cron="*/5 * * * * *") :通过cron表达式定义规则

c.上述方法写好后启动服务看下控制台结果:

2.异步调用

a.首先在spring boot主类上使用注解@EnableAsync启动异步调用

package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
//启动异步调用
@EnableAsync
@SpringBootApplication
public class DemoApplication {
 public static void main(String[] args) {
 SpringApplication.run(DemoApplication.class, args);
 }
}

b.sping boot异步调用很简单,只需使用@Async注解标明方法(接口方法)异步

package com.example.demo.test1.component;
public interface TaskComponent {
 void test1() throws Exception;
 void test2() throws Exception;
 void test3() throws Exception;
}
package com.example.demo.test1.component.impl;
import java.util.Random;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import com.example.demo.test1.component.TaskComponent;
@Component
public class TaskComponentImpl implements TaskComponent {
 public static Random random = new Random();
 @Override
 @Async
 public void test1() throws InterruptedException {
 System.out.println("开始做任务一");
 long start = System.currentTimeMillis();
 Thread.sleep(random.nextInt(10000));
 long end = System.currentTimeMillis();
 System.out.println("完成任务一,耗时:" + (end - start) + "毫秒");
 }
 @Override
 @Async
 public void test2() throws InterruptedException {
 System.out.println("开始做任务二");
 long start = System.currentTimeMillis();
 Thread.sleep(random.nextInt(10000));
 long end = System.currentTimeMillis();
 System.out.println("完成任务二,耗时:" + (end - start) + "毫秒");
 }
 @Override
 @Async
 public void test3() throws InterruptedException {
 System.out.println("开始做任务三");
 long start = System.currentTimeMillis();
 Thread.sleep(random.nextInt(10000));
 long end = System.currentTimeMillis();
 System.out.println("完成任务三,耗时:" + (end - start) + "毫秒");
 }
}

c.使用测试类进行测试:

package com.example.demo;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.test.context.junit4.SpringRunner;
import com.example.demo.test1.component.TaskComponent;
@RunWith(SpringRunner.class)
// 引入SpringBootTest并生成随机接口
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class AsyncTest {
 // 注入随机接口
 @LocalServerPort
 private int port;
 @Autowired
 private TaskComponent taskComponent;
 @Test
 public void testTask() {
 try {
 taskComponent.test1();
 taskComponent.test2();
 taskComponent.test3();
 System.out.println("执行主线程");
 // 主线程休眠10秒等待上述异步方法执行
 Thread.sleep(10000);
 }
 catch (Exception e) {
 System.out.println(e);
 }
 }
}

执行结果如下;可以看出三个异步方法互不影响,且不影响主线程的运行

执行主线程
开始做任务一
开始做任务二
开始做任务三
完成任务一,耗时:1401毫秒
完成任务二,耗时:4284毫秒
完成任务三,耗时:5068毫秒

d.对于这些异步执行的调用往往会给我们带来思考是不是异步调用越多越好,答案当然是否;所以在这里引入线程池来进行异步调用控制:

在spring boot主类上标注线程池:

package com.example.demo;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
//启动定时任务
@EnableScheduling
@SpringBootApplication
public class DemoApplication {
 public static void main(String[] args) {
 SpringApplication.run(DemoApplication.class, args);
 }
 // 启动异步调用
 @EnableAsync
 @Configuration
 class TaskPoolConfig {
 // 核心线程数(setCorePoolSize)10:线程池创建时候初始化的线程数
 // 最大线程数(setMaxPoolSize)20:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
 // 缓冲队列(setQueueCapacity)200:用来缓冲执行任务的队列
 // 允许线程的空闲时间(setKeepAliveSeconds)60秒:当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
 // 线程池名的前缀(setThreadNamePrefix):设置好了之后可以方便我们定位处理任务所在的线程池
 // 线程池对拒绝任务的处理策略(setRejectedExecutionHandler):这里采用了CallerRunsPolicy策略,当线程池没有处理能力的时候,该策略会直接在 execute
 // 方法的调用线程中运行被拒绝的任务(setWaitForTasksToCompleteOnShutdown);如果执行程序已关闭,则会丢弃该任务
 // setWaitForTasksToCompleteOnShutdown(true)该方法就是这里的关键,用来设置线程池关闭的时候等待所有任务都完成再继续销毁其他的Bean,这样这些异步任务的销毁就会先于Redis线程池的销毁。
 // 同时,这里还设置了setAwaitTerminationSeconds(60),该方法用来设置线程池中任务的等待时间,如果超过这个时候还没有销毁就强制销毁,以确保应用最后能够被关闭,而不是阻塞住。
 @Bean("taskExecutor")
 public Executor taskExecutor() {
 ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
 executor.setCorePoolSize(10);
 executor.setMaxPoolSize(20);
 executor.setQueueCapacity(200);
 executor.setKeepAliveSeconds(60);
 executor.setThreadNamePrefix("taskExecutor-");
 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
 executor.setWaitForTasksToCompleteOnShutdown(true);
 executor.setAwaitTerminationSeconds(60);
 return executor;
 }
 }
}

在方法实现类上使用@Async的同时标注线程池:

package com.example.demo.test1.component.impl;
import java.util.Random;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import com.example.demo.test1.component.TaskComponent;
@Component
public class TaskComponentImpl implements TaskComponent {
 public static Random random = new Random();
 @Override
 @Async("taskExecutor")
 public void test1() throws InterruptedException {
 System.out.println("开始做任务一");
 long start = System.currentTimeMillis();
 Thread.sleep(random.nextInt(10000));
 long end = System.currentTimeMillis();
 System.out.println("完成任务一,耗时:" + (end - start) + "毫秒");
 }
 @Override
 @Async("taskExecutor")
 public void test2() throws InterruptedException {
 System.out.println("开始做任务二");
 long start = System.currentTimeMillis();
 Thread.sleep(random.nextInt(10000));
 long end = System.currentTimeMillis();
 System.out.println("完成任务二,耗时:" + (end - start) + "毫秒");
 }
 @Override
 @Async("taskExecutor")
 public void test3() throws InterruptedException {
 System.out.println("开始做任务三");
 long start = System.currentTimeMillis();
 Thread.sleep(random.nextInt(10000));
 long end = System.currentTimeMillis();
 System.out.println("完成任务三,耗时:" + (end - start) + "毫秒");
 }
}

再次调用测试来发现结果没什么区别:

执行主线程
开始做任务一
开始做任务二
开始做任务三
完成任务一,耗时:1117毫秒
完成任务二,耗时:3964毫秒
完成任务三,耗时:8886毫秒

接着我们修改线程池线程数为2:

executor.setCorePoolSize(2);
executor.setMaxPoolSize(2);

再次启动测试类可以看到,同时执行的线程数为2,只有等待前一个线程结束才能执行一个新的线程;

执行主线程
开始做任务一
开始做任务二
完成任务二,耗时:620毫秒
开始做任务三
完成任务一,耗时:2930毫秒
完成任务三,耗时:4506毫秒

3.demo地址:链接地址

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持澳门金沙网上娱乐。

相关文章

  • Java中excel表数据的批量导入方法

    Java中excel表数据的批量导入方法

    这篇文章主要为大家详细介绍了Java中excel表数据的批量导入方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-05-05
  • springboot自动配置没有生效的问题定位(条件断点)

    springboot自动配置没有生效的问题定位(条件断点)

    这篇文章主要介绍了springboot自动配置未生效问题定位,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,下面我们来学习一下吧
    2019-06-06
  • 关于java中Map的九大问题分析

    关于java中Map的九大问题分析

    这篇文章主要为大家详细分析了关于java中Map的九大问题,感兴趣的小伙伴们可以参考一下
    2016-08-08
  • SpringBoot与Dubbo整合的方式详解

    SpringBoot与Dubbo整合的方式详解

    这篇文章主要介绍了SpringBoot与Dubbo整合的方式详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-09-09
  • 详解 maven的pom.xml用<exclusion>解决版本问题

    详解 maven的pom.xml用<exclusion>解决版本问题

    这篇文章主要介绍了详解 maven的pom.xml用<exclusion>解决版本问题的相关资料,希望通过本文能帮助到大家,需要的朋友可以参考下
    2017-09-09
  • java实现的冒泡排序算法示例

    java实现的冒泡排序算法示例

    这篇文章主要介绍了java实现的冒泡排序算法,结合实例形式分析了冒泡排序算法的具体操作步骤与实现技巧,需要的朋友可以参考下
    2017-01-01
  • Java并发编程之性能、扩展性和响应

    Java并发编程之性能、扩展性和响应

    这篇文章主要介绍了Java并发编程之性能、扩展性和响应,重点在于多线程应用程序的性能问题,给性能和扩展性下一个定义,然后再仔细学习一下Amdahl法则,感兴趣的小伙伴们可以参考一下
    2016-02-02
  • 如何优雅的处理Spring Boot异常信息详解

    如何优雅的处理Spring Boot异常信息详解

    这篇文章主要给大家介绍了关于如何优雅的处理Spring Boot异常信息的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用Spring Boot具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-04-04
  • java教程之对象序列化使用基础示例详解

    java教程之对象序列化使用基础示例详解

    所谓对象序列化就是将对象的状态转换成字节流,以后可以通过这些值再生成相同状态的对象,下面详细介绍一下java对象的序列化使用方法
    2014-01-01
  • java调用7zip解压压缩包的实例

    java调用7zip解压压缩包的实例

    下面小编就为大家带来一篇java调用7zip解压压缩包的实例。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-09-09

最新评论