Springboot @Async及线程池的使用和扩展

简介: Springboot @Async及线程池的使用和扩展

 最近在看阿里的JAVA开发手册,说到 线程资源必须通过线程池提供,不允许在应用中自行显式创建线程(new Thread()这种)。

首先在springboot中,它已经给我们提供了很方便的异步和线程池机制。实现异步只要加一个注解@Async,就可以实现了

阿里的JAVA开发手册还说到:使用线程池的好处是减少在创建和销毁线程上所消耗的时间以及系统资源的开销,解决资源不足的问题。如果不使用线程池,有可能造成系统创建大量同类线程而导致消耗完内存或者“过度切换”的问题

Spring是通过任务执行器(TaskExecutor)来实现多线程和并发编程,使用ThreadPoolTaskExecutor来创建一个基于线城池的TaskExecutor

1、开启异步任务

本文springboot版本:

2.0.6.RELEASE

image.gif

在启动类上加注解

@EnableAsync

image.gif

2、配置类 TaskPoolConfig

@Configuration
public class TaskPoolConfig {
    @Bean("taskExecutor")
    public Executor taskExecutor() {
        ThreadPoolTaskScheduler executor = new ThreadPoolTaskScheduler();
        //最大线程数30
        executor.setPoolSize(30);
        //线程池名的前缀
        executor.setThreadNamePrefix("taskExecutor-");
        //设置线程池关闭的时候等待所有任务都完成再继续销毁其他的Bean
        executor.setWaitForTasksToCompleteOnShutdown(true);
        //设置线程池中任务的等待时间
        executor.setAwaitTerminationSeconds(60);
        //当线程池没有处理能力的时候,该策略会直接在 execute 方法的调用线程中运行被拒绝的任务;如果执行程序已关闭,则会丢弃该任务
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return executor;
    }
}

image.gif

值得留意的是  上面的方法名称为taskExecutor

这里我没有用网上更常见的ThreadPoolTaskExecutor 而是用了ThreadPoolTaskScheduler

注意:

ThreadPoolTaskExecutor 和ThreadPoolTaskScheduler都是ThreadPoolExecutor的包装

区别是ThreadPoolTaskScheduler实现了TaskScheduler接口,仅仅多实现这个接口

3、改造service层服务

编写一个测试接口CommonService ,和其实现类CommonServiceImpl

public interface CommonService {
    void executeAsync();
}

image.gif

@Service
public class CommonServiceImpl implements CommonService {
    @Async("taskExecutor")
    @Override
    public void executeAsync() {
        for (int i=0;i<6;i++) {
            System.out.println( "现在i的值--->>:"+i );
            try{
                Thread.sleep(1000);
            }catch(Exception e){
                e.printStackTrace();
            }
        }
    }
}

image.gif

@Async("taskExecutor")     表明executeAsync方法进入的线程池是taskExecutor方法创建的

4、TestController

@RestController
public class TestController {
    @Autowired
    CommonService commonService;
    @GetMapping("/test/executeAsync")
    public String testTASK() {
        commonService.executeAsync();
        return "http请求已结束";
    }
}

image.gif

5、测试

我们用浏览器来测试一下:

image.png

发现当浏览器显示上述提示时,控制台还在打印以下信息,表明该方法以及异步

image.png

6、拓展

 虽然现在线程池能其作用,但是还不清楚线程池的具体使用情况,有多少线程在执行,多少在队列中等待呢?所以创建了一个ThreadPoolTaskExecutor的子类,在每次提交线程的时候都会将当前线程池的运行状况打印出来。这部分参考了这篇博客

springboot线程池的使用和扩展_程序员欣宸的博客-CSDN博客_springboot线程池

public class VisiableThreadPoolTaskScheduler extends ThreadPoolTaskScheduler {
    private static final Logger logger = LoggerFactory.getLogger(VisiableThreadPoolTaskScheduler.class);
    private void showThreadPoolInfo(String prefix){
//        ThreadPoolExecutor threadPoolExecutor = getScheduledExecutor();
        ScheduledThreadPoolExecutor threadPoolExecutor = getScheduledThreadPoolExecutor();
        if(null==threadPoolExecutor){
            return;
        }
        logger.info("{}, {},taskCount [{}], completedTaskCount [{}], activeCount [{}], queueSize [{}]",
                this.getThreadNamePrefix(),
                prefix,
                threadPoolExecutor.getTaskCount(),
                threadPoolExecutor.getCompletedTaskCount(),
                threadPoolExecutor.getActiveCount(),
                threadPoolExecutor.getQueue().size());
    }
    @Override
    public void execute(Runnable task) {
        showThreadPoolInfo("1. do execute");
        super.execute(task);
    }
    @Override
    public void execute(Runnable task, long startTimeout) {
        showThreadPoolInfo("2. do execute");
        super.execute(task, startTimeout);
    }
    @Override
    public Future<?> submit(Runnable task) {
        showThreadPoolInfo("1. do submit");
        return super.submit(task);
    }
    @Override
    public <T> Future<T> submit(Callable<T> task) {
        showThreadPoolInfo("2. do submit");
        return super.submit(task);
    }
    @Override
    public ListenableFuture<?> submitListenable(Runnable task) {
        showThreadPoolInfo("1. do submitListenable");
        return super.submitListenable(task);
    }
    @Override
    public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
        showThreadPoolInfo("2. do submitListenable");
        return super.submitListenable(task);
    }
}

image.gif

注意这里是:

getScheduledThreadPoolExecutor()

image.gif

然后修改上面的 TaskPoolConfig  文件

//        ThreadPoolTaskScheduler executor = new ThreadPoolTaskScheduler();
        ThreadPoolTaskScheduler executor = new VisiableThreadPoolTaskScheduler();

image.gif

我们不停的刷新浏览器进行测试,

2019-04-27 13:20:51.693  INFO 18228 --- [nio-8080-exec-7] c.z.o.c.VisiableThreadPoolTaskScheduler  : taskExecutor-, 2. do submit,taskCount [88], completedTaskCount [60], activeCount [28], queueSize [0]
现在i的值--->>:0

image.gif

这说明提交任务到线程池的时候,调用的是submit(Callable task)这个方法,当前已经提交了88个任务,完成了60个,当前有28个线程在处理任务,还剩0个任务在队列中等待,线程池的基本情况一路了然:P



相关文章
|
17小时前
|
前端开发 Java 应用服务中间件
Springboot对MVC、tomcat扩展配置
Springboot对MVC、tomcat扩展配置
|
17小时前
|
监控 Java Spring
Spring Boot中一般如何使用线程池?
在Spring Boot应用程序中,合理地使用线程池可以有效地提高系统的性能和并发处理能力。本文将深入探讨Spring Boot中如何一般性地使用线程池,包括线程池的配置、使用方式以及一些最佳实践。
17 0
|
17小时前
|
Java C++ Spring
谈谈springboot里面的守护线程与本地线程
【4月更文挑战第18天】在Spring Boot中,线程的概念同Java标准线程模型一致,即区分为守护线程和用户线程。Spring Boot本身并不直接提供创建守护线程或用户线程的特殊机制,但它允许你通过标准Java方式或者利用Spring的框架特性来管理这些线程
41 2
|
17小时前
|
Java Spring
Springboot如何使用线程池
Springboot如何使用线程池
|
17小时前
|
Java Spring
springboot单类集中定义线程池
该内容是关于Spring中异步任务的配置和使用步骤。首先,在启动类添加`@EnableAsync`注解开启异步支持。然后,自定义线程池类`EventThreadPool`,设置核心和最大线程数、存活时间等参数。接着,将线程池bean注入到Spring中,如`@Bean(&quot;RewardThreadPool&quot;)`。最后,在需要异步执行的方法上使用`@Async`注解,例如在一个定时任务类中,使用`@Scheduled(cron = &quot;...&quot;)`和`@Async`结合实现异步定时任务。
19 2
|
17小时前
|
Java 应用服务中间件
Springboot启动的时候初始化的线程池默认配置tomcat
Springboot启动的时候初始化的线程池默认配置tomcat
22 1
|
17小时前
|
Java Spring
SpringBoot+async异步调用接口以及几个任务同时完成和异步接口实现和调用
SpringBoot+async异步调用接口以及几个任务同时完成和异步接口实现和调用
29 0
|
17小时前
|
域名解析 安全 Java
SpringBoot启动的时候初始化的线程池默认配置tomcat
SpringBoot启动的时候初始化的线程池默认配置tomcat
13 1
|
17小时前
|
Java Linux
Springboot 解决linux服务器下获取不到项目Resources下资源
Springboot 解决linux服务器下获取不到项目Resources下资源
|
17小时前
|
Java API Spring
SpringBoot项目调用HTTP接口5种方式你了解多少?
SpringBoot项目调用HTTP接口5种方式你了解多少?
107 2