在日常开发过程中,大多数是基于调用一个方法时,里面业务执行的是同步方式实现,很少用到异步的方式去实现。
同步调用:同步调用指程序按照定义顺序依次执行,每一行程序都必须等待上一行程序执行完成之后才能执行;
异步调用:异步调用指程序在顺序执行时,不等待异步调用的语句返回结果就执行后面的程序。
对比发现异步比同步快很多,节省很多的时间,也会相对提高效率。

一、接下来我们测试同步,我们可以通过一个简单的接口调用实现如图

spring boot 请求 不异步 spring boot 异步接口_spring boot


//测试同步

@RequestMapping(value = “/testSync”)

@ResponseBody

public String testSync()throws InterruptedException {

System.out.println("当前线程名:"+Thread.currentThread().getName());
    LocalTime time1 = LocalDateTime.now().toLocalTime();
    System.out.println("第一次调用时间:"+ time1);

    Thread.sleep(4000);//此时需要处理一个InterruptedException异常
    LocalTime time2 = LocalDateTime.now().toLocalTime();
    System.out.println("第二次调用时间:"+ time2);

    //得出两个时间差
    Duration duration = Duration.between(time1,time2);
    long timeC = duration.toMillis();
    System.out.println("两者相差:"+ (timeC/1000)+"秒");

    return "666666";
}

spring boot 请求 不异步 spring boot 异步接口_spring boot 请求 不异步_02


从结果来看,我们可也看到同步是在我们上一个执行完才开始执行的,中间会有个等待的时间,比如我们在记录日志时候就可以通过异步方式来实现,不需要等待。

二、我们来试试异步方式调用一个程序的结果,我们使用的是springboot,接下来我们采用两种方式来实现看看,
1.使用@Async和@EnableAsync注解;
(简单介绍一下,spring从3.0版本开始支持异步调用,在方法或者类上一个@Async注解就可以,注意这个类不能是加了@Configuration注解,否则不支持,原因@Configuration注解会对当前类进行代理增强,这个时候返回的类是一个经过代理的类,这个时候的方法可能已经不是原方法了。
在3.1版本的时候加上了@EnableAsync注解,基于@Import注解进行扩展的)
2.通过自定义多线程完成;

**1.**我们自定义多线程

如图所示

spring boot 请求 不异步 spring boot 异步接口_spring boot 请求 不异步_03

//	测试异步
    @RequestMapping(value = "/testAsync")
    @ResponseBody
    public String testAsync()throws InterruptedException {
    System.out.println("controller当前线程名:"+Thread.currentThread().getName());
    LocalTime time1 = LocalDateTime.now().toLocalTime();
    System.out.println("第一次调用时间:"+ time1);

    Thread thread = new Thread(new TestAsync());
    thread.start();
    //Thread.sleep(4000);//此时需要处理一个InterruptedException异常
    LocalTime time2 = LocalDateTime.now().toLocalTime();
    System.out.println("第二次调用时间:"+ time2);
    //得出两个时间差
    Duration duration = Duration.between(time1,time2);
    long timeC = duration.toMillis();
    System.out.println("1号结果两者相差:"+ (timeC/1000)+"秒");

    return "666666";
}

我们再写一个实现Runnable接口

把从同步方式抽出来方法或者业务放进线程执行体中。

如图

spring boot 请求 不异步 spring boot 异步接口_spring boot 请求 不异步_04

public class TestAsync implements Runnable {

@Override
public void run() {
    System.out.println("Async当前线程名称:"+Thread.currentThread().getName());
    LocalTime time1 = LocalDateTime.now().toLocalTime();
    System.out.println("第一次调用时间:"+ time1);
    try{
        Thread.sleep(3000);
    }catch (InterruptedException e){
        e.printStackTrace();
    }
    LocalTime time2 = LocalDateTime.now().toLocalTime();
    System.out.println("第二次调用时间:"+ time2);

    //得出两个时间差
    Duration duration = Duration.between(time1,time2);
    long timeC = duration.toMillis();
    System.out.println("2号结果两者时间相差:"+ (timeC/1000)+"秒");
}
}

然后我们启动执行后,可以看到执行结果

spring boot 请求 不异步 spring boot 异步接口_java_05


我们可以看到2号结果在最后打印,说明异步处理成功,调用controller中1号结果方法不需要等待2号结果那个方法执行完。

2.我们来使用@Async和@EnableAsync注解进行处理

首先我们新建一个配置类

spring boot 请求 不异步 spring boot 异步接口_spring boot_06

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurerSupport;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@Configuration
@EnableAsync
public class AsyncConfigurer extends AsyncConfigurerSupport {

@Bean
public ThreadPoolTaskExecutor asyncExecutor(){
    ThreadPoolTaskExecutor threadPoolExecutor = new ThreadPoolTaskExecutor();
    // 设置核心线程数
    threadPoolExecutor.setCorePoolSize(3);
    // 设置最大线程数
    threadPoolExecutor.setMaxPoolSize(3);
    // 等待所有任务结束后再关闭线程池
    threadPoolExecutor.setWaitForTasksToCompleteOnShutdown(true);
    threadPoolExecutor.setAwaitTerminationSeconds(60*15);
    return threadPoolExecutor;
}
}

*这个类也试了一下,去掉也能执行。

我们弄个测试方法

spring boot 请求 不异步 spring boot 异步接口_多线程_07

//测试异步 注解方式
@RequestMapping(value = "/testAsyncZhuJie")
@ResponseBody
public String testAsyncZhuJie()throws InterruptedException {

    System.out.println("controller中当前线程名:"+Thread.currentThread().getName());
    LocalTime time1 = LocalDateTime.now().toLocalTime();
    System.out.println("controller中第一次调用时间:"+ time1);
    //业务调用
    asyncService.testAsyncZhuJie();
    Thread.sleep(4000);//此时需要处理一个InterruptedException异常
    LocalTime time2 = LocalDateTime.now().toLocalTime();
    System.out.println("controller中第二次调用时间:"+ time2);
    //得出两个时间差
    Duration duration = Duration.between(time1,time2);
    long timeC = duration.toMillis();
    System.out.println("controller中1号结果两者相差:"+ (timeC/1000)+"秒");

    return "666666";
}

然后在service实现类中写了个方法方便调用

spring boot 请求 不异步 spring boot 异步接口_spring boot 请求 不异步_08

@Async
@Override
public void testAsyncZhuJie() {
    System.out.println("Service中Async当前线程名称:"+Thread.currentThread().getName());
    LocalTime time1 = LocalDateTime.now().toLocalTime();
    System.out.println("Service中第一次调用时间:"+ time1);
    try{
        Thread.sleep(3000);
    }catch (InterruptedException e){
        e.printStackTrace();
    }
    LocalTime time2 = LocalDateTime.now().toLocalTime();
    System.out.println("Service中第二次调用时间:"+ time2);

    //得出两个时间差
    Duration duration = Duration.between(time1,time2);
    long timeC = duration.toMillis();
    System.out.println("Service中2号结果两者时间相差:"+ (timeC/1000)+"秒");
     }

执行结果如下

spring boot 请求 不异步 spring boot 异步接口_多线程_09


至此我们可以看到,如果service方法在最后打印,说明controller在执行后不需要等待service全部执行完才走,注意这个@Async注解没有会失效,结果就是等service全部执行完了,controller才走接下来的方法。

以上都是个人亲测,也是日常开发过程中所用的方式。如果有什么不对的地方,希望大家指正,谢谢了!