SpringBoot使用异步调用提高接口访问速度

开启异步调用

在主函数里面加上@EnableAsync

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;

@SpringBootApplication
@EnableAsync
public class DemoApplication {

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

使用默认异步调用

在接口上加@Async,那么此接口就是异步的了

@Service
public class TestService {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Async
    public void asyncMethod() {
        sleep();
        logger.info("异步方法内部线程名称:{}", Thread.currentThread().getName());
    }

    public void syncMethod() {
        sleep();
    }

    private void sleep() {
        try {
        	//让当前线程阻塞2秒钟
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

查看效果:

@RestController
public class TestController {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private TestService testService;

    @GetMapping("async")
    public void testAsync() {
        long start = System.currentTimeMillis();
        logger.info("异步方法开始");

        testService.asyncMethod();

        logger.info("异步方法结束");
        long end = System.currentTimeMillis();
        logger.info("总耗时:{} ms", end - start);
    }

    @GetMapping("sync")
    public void testSync() {
        long start = System.currentTimeMillis();
        logger.info("同步方法开始");

        testService.syncMethod();

        logger.info("同步方法结束");
        long end = System.currentTimeMillis();
        logger.info("总耗时:{} ms", end - start);
    }
}

这样可以看出这两个接口之间的差异,因为被@Async标注后的方法是异步执行的,所以他不会等待阻塞!

自定义线程池

定义线程池我所知的有两个简便方法一个是用Executors工具类来快速定义,但是在《阿里巴巴开发手册》里这种做法被明令禁止,他们用ThreadPoolExecutor来创建线程池。而在SpringBoot里也有封装好的线程池ThreadPoolTaskExecutor,你只需要自己手动配置下就可以了,过程大致类似ThreadPoolExecutor

@Configuration
public class AsyncPoolConfig {

    @Bean
    public ThreadPoolTaskExecutor asyncThreadPoolTaskExecutor(){
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(20);
        executor.setMaxPoolSize(200);
        executor.setQueueCapacity(25);
        executor.setKeepAliveSeconds(200);
        executor.setThreadNamePrefix("Async-Thread-");
        //是否等待所有线程执行完毕才关闭线程池,默认值为false。
        executor.setWaitForTasksToCompleteOnShutdown(true);
//        awaitTerminationSeconds:waitForTasksToCompleteOnShutdown的等待的时长,默认值为0,即不等待。
        executor.setAwaitTerminationSeconds(60);

        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());

        executor.initialize();
        return executor;
    }
}

要使用该线程池,只需要在@Async注解上指定线程池Bean名称即可:

package com.example.demo.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;

import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

@Service
public class TestService {

    private Logger logger = LoggerFactory.getLogger(this.getClass());
    
    @Async("asyncThreadPoolTaskExecutor")
    public void asyncMethod() {
        sleep();
        logger.info("异步方法内部线程名称:{}", Thread.currentThread().getName());
    }

    public void syncMethod() {
        sleep();
    }

    private void sleep() {
        try {
            TimeUnit.SECONDS.sleep(2);
            logger.info("线程:{} 休眠结束!",Thread.currentThread().getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

线程池的配置其实还是比较讲究的,要结合自己的项目和实际环境来配置!

处理回调

有点基础的小伙伴都知道在多线程里面想要有返回值,我们要实现Callable接口,Future来接收回调值

@Async("asyncThreadPoolTaskExecutor")
public Future<String> asyncMethod() {
    sleep();
    logger.info("异步方法内部线程名称:{}", Thread.currentThread().getName());
    return new AsyncResult<>("hello async");
}

控制器:

@GetMapping("async")
public String testAsync() throws Exception {
    long start = System.currentTimeMillis();
    logger.info("异步方法开始");

    Future<String> stringFuture = testService.asyncMethod();
    String result = stringFuture.get();
    logger.info("异步方法返回值:{}", result);
    
    logger.info("异步方法结束");

    long end = System.currentTimeMillis();
    logger.info("总耗时:{} ms", end - start);
    return stringFuture.get();
}

这次我们会发现,似乎比上面的同步方法慢了,因为Futureget方法为阻塞方法,只有当异步方法返回内容了,程序才会继续往下执行。

深度了解请点击

给个关注吧

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值