SpringBoot专栏:配置异步调用结合线程池玩出新花样,做不一样的教程

SpringBoot专栏:配置异步调用结合线程池玩出新花样,做不一样的教程

前言

异步(async)方法:用于异步执行其他工作,然后立即返回到调用方法

本章节将讲解springboot 如何配置异步方法,朋友有留言说期待看到springCloud等高阶技能点方面的文章,好的,不用着急,马上即将开启下一专栏,毕竟微服务才是自己所擅长的,SpringBoot专栏即将结束,但是在即将结束的几章里面,也不会让朋友失望,简单的springboot异步调用配置也尝试加一些其他的知识点。

虽然简单,但是我们要学着玩出不一样的demo(通过demo学习更多的技能点)

希望demo不再是demo而是让我们学习技能点最快速的方式。

SpringBoot专栏:配置异步调用结合线程池玩出新花样,做不一样的教程

Demo开始

pom引入

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>

创建一个service(注意sayHallo 加上  @Async)

@Service
public class SleepService {

    /**
     *异步问候
     * @param name
     * @return
     */
    @Async
   public Future<String>   sayHallo(String name){
       try {
           //休眠10秒
           Thread.sleep(10000);
       } catch (InterruptedException e) {
           e.printStackTrace();
       }
       return  new AsyncResult<String>("异步您好"+name);
   }

    /**
     *问候【非异步】
     * @param name
     * @return
     */
    public  String  sayHallo1(String name){
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return  "非异步,您好-》"+name;
    }
}

创建controller

SpringBoot专栏:配置异步调用结合线程池玩出新花样,做不一样的教程

启动类(注意加上@EnableAsync )


@SpringBootApplication
@EnableAsync
public class Springboot10EmailAsyncApplication   extends AsyncConfigurerSupport {

	public static void main(String[] args) {
		SpringApplication.run(Springboot10EmailAsyncApplication.class, args);
	}
	//初始化线程池
	@Override
	public Executor getAsyncExecutor() {
		ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
		executor.setCorePoolSize(2);
		executor.setMaxPoolSize(2);
		executor.setQueueCapacity(500);
		executor.setThreadNamePrefix("springboot-async-");
		executor.initialize();
		return executor;
	}
}

测试分析

但访问controller: ip/hello/springboot  

当访问:异步方法sayHallo()的服务,此时因为是异步的所以controller可以快速的返回处理结果

当访问:非异步方法sayHallo1()的服务,因为是非异步的,业务方法中还有10秒的休眠,所以controller需要等待业务方法处理完后方可返回处理结果。

End?

汇总:异步方法实现很简单共2步:

1)启动类@EnableAsync开启异步任务

2)业务方法上@Async 表明是一个异步任务

是不是本章节就结束呢?No

细心的同学会发现了sayHallo()方法返回的是Future类型,那我们是不也应该来了解下。

启动类初始化了线程池,那是不是也应该了解下?

之前SpringBoot 事件监听回调知识点,是不是这个demo也可"小试牛刀"一下?

所以有了下面的一个测试方法

温故知新

新业务:当项目启动之后(监听回调),采用线程池异步调用sayHall()方法(线程池和Future用法),并分析测试结果(收获新旧技能点)

新的监听测试类

@Component
public class TestListener implements CommandLineRunner {
    private static final Logger logger = LoggerFactory.getLogger(CommandLineRunner.class);

    @Autowired
    private final SleepService sleepService;

    public TestListener(SleepService sleepService) {
        this.sleepService = sleepService;
    }

    @Override
    public void run(String... args) throws Exception {
        long start = System.currentTimeMillis();
        Future<String> name1 = sleepService.sayHallo("springBoot-1");
        Future<String> name2 = sleepService.sayHallo("springBoot-2");
        Future<String> name3 = sleepService.sayHallo("springBoot-3");
        Future<String> name4 = sleepService.sayHallo("springBoot-4");
        logger.info("异步运行用时: " + (System.currentTimeMillis() - start));


        logger.info("线程池初始化调用,得到返回结果");
        logger.info("开始测试1{}",name1.get());
        logger.info("开始测试2{}",name2.get());
        logger.info("开始测试3{}",name3.get());
        logger.info("开始测试4{}",name4.get());


    }
}

输出日志结果:

2018-12-30 16:18:36.378  INFO 8580 --- [  restartedMain] o.s.boot.CommandLineRunner               : 异步运行用时: 9
2018-12-30 16:18:36.378  INFO 8580 --- [  restartedMain] o.s.boot.CommandLineRunner               : 线程池初始化调用,得到返回结果
2018-12-30 16:18:46.389  INFO 8580 --- [  restartedMain] o.s.boot.CommandLineRunner               : 开始测试1异步您好springBoot-1
2018-12-30 16:18:46.389  INFO 8580 --- [  restartedMain] o.s.boot.CommandLineRunner               : 开始测试2异步您好springBoot-2
2018-12-30 16:18:56.390  INFO 8580 --- [  restartedMain] o.s.boot.CommandLineRunner               : 开始测试3异步您好springBoot-3
2018-12-30 16:18:56.390  INFO 8580 --- [  restartedMain] o.s.boot.CommandLineRunner               : 开始测试4异步您好springBoot-4

分析

1.测试类 implements CommandLineRunner:表明这是一个事件监听回调,等项目启动成功运行测试方法run()

2.“异步运行用时: 9”  日志表明:上面4个调用方法,是异步的,所以用时9毫秒(异步调用)

3.“开始测试1..”"开始测试2.."  打印日志时间是16:18:46 而其它是稍微久一点:因为在配置线程池的时候最大线程为2

线程池部分参数

SpringBoot专栏:配置异步调用结合线程池玩出新花样,做不一样的教程

4.什么是Future模式

     Future模式是多线程开发中非常常见的一种设计模式。它的核心思想是异步调用。当我们需要调用一个函数方法时。如果这个函数执行很慢,那么我们就要进行等待。但有时候,我们可能并不急着要结果。因此,我们可以让被调用者立即返回,让他在后台慢慢处理这个请求。对于调用者来说,则可以先处理一些其他任务,在真正需要数据的场合再去尝试获取需要的数据。

     使用Future模式,获取数据的时候无法立即得到需要的数据。而是先拿到一个契约,你可以再将来需要的时候再用这个契约去获取需要的数据,

至于Future其他的方法我们可以继续了解,在此不展开深入讨论(后面并发、多线程编程会详细介绍)

End?Yes

本章节到此就结束了,也希望大家可以

1)丢异步方法有个简单的调用(自然很简单)

2)温故而知新希望大家通过最后一个测试类能对线程池、Future、事件异步回调有个进一步了解。

最后谢谢大家

坚持写作1个月了,现在发现朋友的一次转发、关注是对本文的最大支持,鼓励下,转发支持一次,谢谢

更多信息可以咨询 @架构师速成记