spring中的线程池相关

53 阅读3分钟

线程池定义

频繁的进行线程创建和销毁是十分消耗资源的,事先建好一些线程备用并视使用情况决定继续保留或销毁,而且也更加便于线程的管理,这样的功能便是线程池。

核心线程个数即是初始化时的线程个数,后续根据需要会临时增加线程个数,直至到达指定的最大线程数。

核心线程一般是cpu个数的2倍,最大线程一般是cpu个数的4倍。

线程池工作流程

任务提交后,

先判断池子中核心线程有没有空闲的,

有则直接用,也就是由这个空闲的核心线程去执行任务

没有再看缓冲队列中还有没有位置,

有位置,则放缓冲队列中,核心线程手头上任务执行完了会来队列中拿任务执行

没有位置,则再看线程池内线程数量是否已达到最大值,

没满,创建线程执行任务(也就是说用创建线程的方式执行任务会比排在缓冲队列中的先执行,因为要排队啊)

满了,则按饱和策略处理没法执行的任务

0

饱和策略

当工作队列满且线程个数达到maximunPoolSize后所采取的策略

如采用默认策略,池子、队列都满了,则抛出异常

AbortPolicy:默认策略;新任务提交时直接抛出未检查的异常RejectedExecutionException,该异常可由调用者捕获。 CallerRunsPolicy:既不抛弃任务也不抛出异常,使用调用者所在线程运行新的任务。(这种池子满了可能就无法体现出异步线程的效果) DiscardPolicy:丢弃新的任务,且不抛出异常。 DiscardOldestPolicy:调用poll方法丢弃工作队列队头的任务,然后尝试提交新任务 自定义策略:根据用户需要定制。

java的ThreadPoolExecutor

  1. 随用随new

  2. 在类的静态属性中new

  3. 启动时生成bean加到spring容器,

注:类若是单例,要注意手动销毁线程池,不然他一直占用资源,不过好像也不大。

Springboot的ThreadPoolTaskExecutor

  1. spring内对其做了自动装配,自己配置参数即可,它内部也有默认配置

  2. 自定义bean加到spring容器中

注:spring支持用注解的方式走异步线程,要先开启@EnableAsync

@Service public class AsyncTest { protected final Logger logger = LoggerFactory.getLogger(this.getClass()); // 注意启动类上要加@EnableAsync // 这里如果不填,使用的是默认的线程池 // 可以填入自己自定义的线程池bean名,如:@Async("definedTaskPoolExecutor") @Async public void hello(String name){ //这里使用logger 方便查看执行的线程是什么 logger.info("异步线程启动 started."+name); } } CLASS... @Bean("myThreadPoolTaskExecutor") public ThreadPoolTaskExecutor myExecutor(){ ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor(); ... return threadPoolTaskExecutor; }

核心线程数 spring.task.execution.pool.core-size=8 # 最大线程数 spring.task.execution.pool.max-size=16 # 空闲线程存活时间 spring.task.execution.pool.keep-alive=60s # 是否允许核心线程超时 spring.task.execution.pool.allow-core-thread-timeout=true # 线程队列数量 spring.task.execution.pool.queue-capacity=100 # 线程关闭等待 spring.task.execution.shutdown.await-termination=false spring.task.execution.shutdown.await-termination-period= # 线程名称前缀 spring.task.execution.thread-name-prefix=task-

在spring类中,常以静态属性形式构建形成池

//class public Test{ private static final ThreadPoolExecutor SMS_SEND_EXECUTOR = new ThreadPoolExecutor(10, 20, 30, TimeUnit.SECONDS, new LinkedBlockingQueue<>(512), r -> new Thread(r,SmsService.class.getSimpleName() + "-" + r.hashCode()), new ThreadPoolExecutor.CallerRunsPolicy()); ... }