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

导读:本篇文章讲解 SpringBoot使用异步调用提高接口访问速度,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

开启异步调用

在主函数里面加上@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方法为阻塞方法,只有当异步方法返回内容了,程序才会继续往下执行。

深度了解请点击

给个关注吧

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/16416.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!