线程池创建

文章介绍了Spring中使用@Async进行异步调用的方法,以及如何通过ThreadPoolTaskExecutor自定义线程池配置,包括核心线程数、最大线程数、队列容量等参数。同时,文章提到了@Async失效的情况和线程池处理任务的流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、相关注解

@Async是spring为了方便开发人员进行异步调用的出现的,在方法上加入这个注解,spring会从线程池中获取一个新的线程来执行方法,实现异步调用

@EnableAsync表示开启对异步任务的支持,可以放在springboot的启动类上,也可以放在自定义线程池的配置类上,具体看下文

2、自定义线程池


import lombok.Data;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ThreadPoolExecutor;

@EnableAsync
@Configuration
public class ThreadPoolConfig {

    ThreadPoolProperties properties = new ThreadPoolProperties();

    @Bean(name = "taskExecutor")
    public ThreadPoolTaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //核心线程数目 : 池中会保留的最多线程数
        executor.setCorePoolSize(properties.getCorePoolSize());
        //最大线程数目 = 核心线程+救急线程的最大数目
        executor.setMaxPoolSize(properties.getMaxPoolSize());
        executor.setQueueCapacity(properties.getQueueCapacity());
        executor.setThreadNamePrefix(properties.getThreadNamePrefix());
        // 设置线程保持活跃的时间(默认:60)
        //生存时间 - 救急线程的生存时间,生存时间内没有新任务,此线程资源会释放
        executor.setKeepAliveSeconds(properties.getKeepAliveTime());
        // 当任务完成后,长时间无待处理任务时,销毁线程池
        executor.setWaitForTasksToCompleteOnShutdown(properties.isWaitForTasksToCompleteOnShutdown());
        executor.setAwaitTerminationSeconds(properties.getAwaitTerminationSeconds());
        // 设置任务拒绝策略
        /**
         * 4种
         * ThreadPoolExecutor类有几个内部实现类来处理这类情况:
         - AbortPolicy 丢弃任务,抛RejectedExecutionException
         - CallerRunsPolicy 由该线程调用线程运行。直接调用Runnable的run方法运行。
         - DiscardPolicy  抛弃策略,直接丢弃这个新提交的任务
         - DiscardOldestPolicy 抛弃旧任务策略,从队列中踢出最先进入队列(最后一个执行)的任务
         * 实现RejectedExecutionHandler接口,可自定义处理器
         */
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return executor;
    }

    @Data
    class ThreadPoolProperties {

        /**
         * 核心线程数(默认是1):若是IO密集型,cpu核心数*2,若是cpu密集型,cpu核心数
         * 核心线程会一直存活,及时没有任务需要执行
         * 设置allowCoreThreadTimeout=true(默认false)时,核心线程会超时关闭
         * 注意:当线程数小于核心线程数时,即使有线程空闲,线程池也会优先创建新线程处理
         */
        private int corePoolSize = 2;
        /**
         * 最大线程数,系统默认Integer.MAX_VALUE
         */
        private int maxPoolSize = 5;
        /**
         * 允许线程空闲时间(单位:默认为秒,默认60S)
         * 当线程空闲时间达到keepAliveTime时,线程会退出,直到线程数量=corePoolSize
         * 如果allowCoreThreadTimeout=true,则会直到线程数量=0
         */
        private int keepAliveTime;
        /**
         * 缓冲队列大小,系统默认Integer.MAX_VALUE
         * 注意:这个值肯定要改小,不然任务陡增时,都堆在队列中(队列值大),
         * 核心线程数就那几个,无法很快执行队列中的任务,
         * 就会延长响应时间,阻塞任务
         */
        private int queueCapacity = 8;
        /**
         * 线程池名前缀,用于监控识别
         */
        private String threadNamePrefix = "asyncTaskExecutor-";

        /**
         * 允许核心线程超时(默认false)
         */
        private boolean allowCoreThreadTimeout = false;

        /**
         * 当任务完成后,长时间无待处理任务时,销毁线程池
         */
        private boolean waitForTasksToCompleteOnShutdown = false;

        private int awaitTerminationSeconds;

    }
}

3、使用@Async调用多线程

@Service
@EnableAsync
public class ThreadPoolServiceImp implements ThreadPoolService {
    
    @Async("taskExecutor")
    @Override
    public void F1(int num)  {
        try {

                System.out.println(
                        Thread.currentThread().getName()
                                +"\t"
                                +Thread.currentThread().getId()
                                +"\t"
                                + new Date()
                                +"\t"
                                +"执行线程: "
                                +num);

                Thread.sleep(500);

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
        }

    }
    
 
}

4、验证使用

public class ThreadPoolControllerTest extends BasiServiceApplicationTests {
    @Autowired
    private ThreadPoolService threadPoolService;
    @Test
    public void f1() throws InterruptedException {
        for (int i = 0; i < 50; i++) {

            threadPoolService.F1(i);
        }

        sleep(10*1000);
    }


}

5、未防止 线程中断:java.lang.InterruptedException: sleep interrupted

测试代码添加:

sleep(10*1000);

6、@Async失效情况:

1、异步方法使用static修饰

2、异步类没有使用@Component注解(或其他注解)导致spring无法扫描到异步类

3、异步方法不能与被调用的异步方法在同一个类中

4、类中需要使用@Autowired或@Resource等注解自动注入,不能自己手动new对象

5、如果使用SpringBoot框架必须在启动类中增加@EnableAsync注解

7、线程池处理任务流程:

当往线程池中提交新任务时,线程池主要流程如下:

核心线程数 -> 线程队列 -> 最大线程数 -> 拒绝策略

如果池中任务数 < corePoolSize (核心线程数),创建新线程立即执行任务

如果池中任务数 > corePoolSize,新任务放到缓存队列当中等待执行

队列满,线程数量<maxPoolSize,新建线程立即执行任务

队列满,线程数量>=maxPoolSize,使用拒绝策略拒绝

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值