全部开发者教程

企业级在线办公系统

大家都知道Java语言是同步执行的,一句代码没执行完,绝不会执行下一句代码。JavaScript默认也是如此的,但是JavaScript里面的Ajax是异步执行的。那么Java语言能不能也拥有异步执行的能力呢?当然可以。

一、为什么要采用异步执行?

有些同学想不明白,为什么要给Java语言增添异步执行?其实很简单,在一个业务流程中,有时候会有一些耗费时间的分支任务,如果把这些琐碎且不重要的任务用异步来执行,那么就可以减轻当前线程的执行压力。

举个例子吧,例如有个电商网站为了吸引新用户注册,给出了赠送一年优酷会员的优惠。如果我们采用同步的执行方式,用户帐户开通之后,当前线程还要调用优酷系统的接口,开通会员帐户,并且充值一年会员。整个流程加起来还是挺耗费时间的,让新注册用户等待一两分钟才能收到注册成功的通知,用户心里肯定会怀疑:这是什么破电商网站,注册个会员就要好几分钟,我要是买东西不得卡成翔啊。

如果我们采取异步执行的方式,电商帐户开通之后,我们把开通优酷会员的任务交给其他线程去做,当前线程就不用负责了,直接返回给用户注册成功即可。当其他线程开通优酷会员之后,给用户的手机发一个短信通知即可。你看,采用了异步执行以后,新用户注册的体验更好了。其实我这里说的异步执行就是由SpringBoot自动把任务交给线程池中某个线程去执行。你以前自己创建线程分配任务的方式,也属于异步执行。只不过有了SpringBoot之后,任务的分配更加自动了。

关于电商网站新用户注册的例子,有的同学可能还有疑问:不用异步执行,我用消息队列来分配任务是不是也行?当然是可行的。刚才我说的异步执行陷于同一个系统中,把分支任务交给其他线程去执行。如果你用的是分布式架构,A系统想要把分支任务分配个B系统去执行,通过消息队列来分配任务完全是可行的,这也算是一种异步执行的方式。

二、创建线程池

为了把任务分配给其他线程,我们首先要配置一个线程池出来。在com.example.emos.api.config包中创建ThreadPoolConfig.java类。

package com.example.emos.api.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ThreadPoolExecutor;

@Configuration
public class ThreadPoolConfig {
    @Bean("AsyncTaskExecutor")
    public AsyncTaskExecutor taskExecutor(){
        ThreadPoolTaskExecutor executor=new ThreadPoolTaskExecutor();
        // 设置核心线程数
        executor.setCorePoolSize(8);
        // 设置最大线程数
        executor.setMaxPoolSize(16);
        // 设置队列容量
        executor.setQueueCapacity(32);
        // 设置线程活跃时间(秒)
        executor.setKeepAliveSeconds(60);
        // 设置默认线程名称
        executor.setThreadNamePrefix("task-");
        // 设置拒绝策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }
}

三、开启SpringBoot异步执行

我们在项目的主类EmosApiApplication.java声明上面加上@EnableAsync注解即可。等将来我们发送邮件的时候,再去编写任务类。

package com.example.emos.api;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.scheduling.annotation.EnableAsync;

@SpringBootApplication
@ServletComponentScan
@Slf4j
@EnableAsync
public class EmosApiApplication {

    public static void main(String[] args) {
        SpringApplication.run(EmosApiApplication.class, args);
    }

}