带着新人学springboot的应用09(springboot+异步任务)

  原本想说说检索的,不过不知道什么鬼,下载ElasticSearch太慢了,仍是放一下,后面有机会再补上!今天就说个简单的东西,来讲说任务。java

  什么叫作任务呢?其实就是类中实现了一个什么功能的方法。常见的任务就是异步任务,定时任务,发邮件。web

  异步任务:其实就是一个很特别的方法,这个方法没有返回值(也能够有返回值,后面会说的),可是方法内部的逻辑会耗费不少时间!例如,用户请求每次到controller,要执行到这个异步方法的时候,咱们只须要命令一个空闲状态的线程去执行它便可,因为没有返回值不影响后续代码的运行,controller直接去执行后续的代码。这样能够极为迅速的响应用户,用户体验很是好。spring

  定时任务:这个其实看名字就知道了,你能够选定一个月的哪一天哪一个小时的具体时分秒,去执行一个方法。这个方法是自动执行的,极大的减轻了咱们的工做量。数据库

  发邮件:这个仍是比较常见的吧!注册什么的大多都要邮件激活,咱们也能够用java程序的方式,来给你邮箱发邮件。数组

  提早准备:大概了解一下javase中多线程和线程池概念,重点是ThreadPoolTaskExecutor这个类。浏览器

 

1.简单说说异步任务和RabbitMQspringboot

  不知道看了我上面说了异步任务,你们有没有想到前面说过的一个东西,就是RabbitMQ啊!这个消息队列,不就是也是这样的吗?生产者发消息给交换器以后,就无论了,也许生产者就能够直接响应用户响应成功了。而内部也许还有交换器发消息给队列,而后消费者消费消息,但这个过程就跟用户就没什么关系了,干吗要用户浪费时间在那瞎等呢?服务器

  就我而言,异步任务和RabbitMQ最大的区别应该是访问量的差别;能够将异步任务看做是简化版RabbitMQ 。多线程

  你想啊,假如你作了一个系统,最大访问量总共那么点人,你还要去用个RabbitMQ去搞这搞那的,麻不麻烦啊。。。异步

  可是假如你在一家大公司,作的系统是给几十万甚至几百万用户用的,那么确定要用RabbitMQ啊。这个时候若是用异步任务,哪有这么多空闲线程去给你执行这个任务啊,并且线程到了一个数目以后,效率反而是下降的。

  补充小知识:你们知不知道服务器怎么处理多个请求的啊?

  假如都是同步任务:请用请求一到,服务器就出用一个线程去执行,而且到了service层以后,假设会有个任务须要几十秒才能执行完毕;那么执行到这里就会卡住了,请求到这里都要卡住几十秒,人多的时候可能还要排队,等时间过了你才会获得响应。

  那就等着呗,然而不巧的是,这个时候又有几千人来来给服务器发请求,因而这几千人每人等几十秒,并且因为服务器又比较水,一会儿开了几千个线程还有点卡因而要等更长时间。(咳,因此越贵的服务器配置高,线程可以开得多,运行速度快,处理多人请求的能力就很牛),因而这几千人用了这个系统以后,心中大骂日了狗了哦,下次不再用这个鬼系统了。 

  那假如是异步任务:仍是用订单/库存系统举例,几千人都在买买买,一时间几千个订单请求到controller,而后调用service(注:service仍是跟上面同样要几十秒),一到service,判断是个异步方法,因而赶忙让处理异步任务的线程过来慢慢处理就好,controller能够直接响应用户“订单成功”。用户极短期就收到响应,因而能够继续买买买。

  这里就要说个东西,那个处理异步方法的线程哪里来的啊?实际上是从异步方法线程池里拿的。你们应该知道链接池啊,是处理与数据库链接问题的,还能设置个数,最大超时时间等等,还能防止频繁的销毁建立线程的资源消耗。这里的线程池也差很少,能够设置个数啊什么的。。。。后面咱们就会试试简单的配置一个链接池专门处理异步任务。

 

2.简单使用异步任务

  建立一个简单的springboot项目,web模块+1.5.xx版本。

  简单写个controller和一个处理逻辑的类,先看看同步处理:

  ok,你能够测试一下,等5秒钟浏览器才会响应,emmm...玛德,等得真烦。。。

 

  测试异步处理,加两个注解就ok了。

  而后此次就能不超过一秒钟,就返回响应成功了,大家也能够本身用System.currentTimeMillis()这个方法去测测时间,这里就很少说了。

  这里就须要考虑了,假如访问量不少,每一个请求都过来调用HelloTask方法,那就要拿到相应数量的处理异步的线程,来处理这个HelloTask方法!

  处理异步任务的线程也是属于服务器的线程啊,线程数太多服务器会很卡的,默认是有线程池的!可是咱们根据本身项目的需求,因而要自定义线程池的一些配置。

  假如线程池里就设置最多30个线程(这里也会有个相似RabbitMq的简单消息队列),那么即便几千人来调用HelloTask方法,那么最多也就拿到30个处理异步的线程,来处理这个方法;至于其余的那么多请求就丢到请求队列里,等这30个线程中某些率先处理完任务的线程就会从这消息队列中拿任务继续处理。

 

3.自定义异步任务的线程池

   刚刚查一下资料,其实也是能够用多线程来作的,只是每次都用多线程比较麻烦,不太小伙伴们能够试试。

  线程池就至关于包装了一下多线程的操做,作了不少配置!就相似ArrayList和Object数组的关系。

   

  在下面方法打印当前线程(注意,这里注解@Async(“本身配置的线程池的名字”),这里能够指定配置的哪一个线程池,能够本身试试,咱们这里要写应该是taskExecutor)

 

 而后运行,打开浏览器,疯狂刷新,控制台打印以下;(注意:能够把线程池中线程数目弄少一点,把sleep时间调整短一点,就能明显看到线程不会按顺序使用了,而是随机的!这个本身能够测试一下)

 

4.给异步方法设置返回值

   前面说的都是异步方法返回值为void的状况,可是有的时候咱们要拿到异步方法的返回值。

  这个逻辑是怎么回事呢?有了返回值还能异步吗?答案是能够的。

  举个例子,当请求到controller,线程就会去执行controller方法,碰到了要执行一个异步方法,因而异步方法立马返回一个Future对象敷衍controller一下(玛德,controller真是老实人...),而后继续执行controller后面的方法,不会停顿;

  这个Future就是异步方法的返回值,只是刚开始尚未数据,等异步方法执行完毕,自动的就会将数据放入Future,比较常见的是利用Future来捕获异常。

  其中,Future是个接口,实现类是AsyncResult,下面就看看修改后的controller:

 

 

  再看看异步方法内部代码:

 

  ok,能够了,运行应用,测试结果以下:

 

  简单的看了看异步任务的用法,应该仍是比较容易的,用起来也没什么难度,就是真实项目碰到的状况可能就会很复杂,要考虑的状况比较多了。

相关文章
相关标签/搜索