这是我参与「第四届青训营 」笔记创作活动的第1天
线程池的好处
池化管理、减小开销。一般情况下的new Thread中,一个用户线程就创建一个内核线程,当请求数量多时,会出现频繁的创建和回收,不便于管理。
线程池的参数
线程池的真正实现类是 ThreadPoolExecutor,其构造方法有如下4种:
// 创建线程池
ThreadPoolExecutor threadPool
= new ThreadPoolExecutor(CORE_POOL_SIZE,
MAXIMUM_POOL_SIZE,
KEEP_ALIVE,
TimeUnit.SECONDS,
sPoolWorkQueue,
sThreadFactory);
// 线程池执行任务
threadPool.execute(new Runnable() {
@Override
public void run() {
}
});
threadPool.shutdown(); // 关闭线程池
-
corePoolSize(核心线程数、初始化线程数)
一般直接写cpu数量Runtime.getRuntime().availableProcessors(),线程池中的数量要多余这个数时,才会去利用空闲的线程。
-
maximumPoolSize(最大线程数)
无空闲线程时,可创建的最大线程数量
cpu密集型:核心数+1
IO密集型:核心数*2
-
keepAliveTime(存活时间)
回收的是非核心线程
-
workQueue(工作队列)
不同任务有不同的策略
| BlockingQueue | 特点 |
|---|---|
| ArrayBlockingQueue | 一个由数组结构组成的有界阻塞队列。 |
| LinkedBlockingQueue | 一个由链表结构组成的有界阻塞队列,在未指明容量时,容量默认为 Integer.MAX_VALUE。 |
| PriorityBlockingQueue | 一个支持优先级排序的无界阻塞队列,对元素没有要求,可以实现 Comparable 接口也可以提供 Comparator 来对队列中的元素进行比较。跟时间没有任何关系,仅仅是按照优先级取任务。 |
| DelayQueue | 类似于PriorityBlockingQueue,是二叉堆实现的无界优先级阻塞队列。要求元素都实现 Delayed 接口,通过执行时延从队列中提取任务,时间没到任务取不出来。 |
| SynchronousQueue | 一个不存储元素的阻塞队列,消费者线程调用 take() 方法的时候就会发生阻塞,直到有一个生产者线程生产了一个元素,消费者线程就可以拿到这个元素并返回;生产者线程调用 put() 方法的时候也会发生阻塞,直到有一个消费者线程消费了一个元素,生产者才会返回。 |
| LinkedBlockingDeque | 使用双向队列实现的有界双端阻塞队列。双端意味着可以像普通队列一样 FIFO(先进先出),也可以像栈一样 FILO(先进后出)。 |
| LinkedTransferQueue | 它是ConcurrentLinkedQueue、LinkedBlockingQueue 和 SynchronousQueue 的结合体,但是把它用在 ThreadPoolExecutor 中,和 LinkedBlockingQueue 行为一致,但是是无界的阻塞队列 |
- handler(拒绝策略)
当达到最大线程数时需要执行的饱和策略。就是管理的线程都繁忙下需要新线程,新来的任务的处理方案
| handler | 特点 |
|---|---|
| AbortPolicy(默认): | 丢弃任务并抛出 RejectedExecutionException 异常。 |
| CallerRunsPolicy: | 由调用线程处理该任务。 |
| DiscardPolicy: | 丢弃任务,但是不抛出异常。可以配合这种模式进行自定义的处理方式。 |
| DiscardOldestPolicy: | 丢弃队列最早的未处理任务,然后重新尝试执行任务。 |
线程池拓展使用
springboot框架提供了@Async注解,帮助我们更方便的将业务逻辑提交到线程池中异步执行
spring中的ThreadPoolTaskExecutor对ThreadPoolExecutor封装,支持线程池的bean化,防止滥用线程池。
声明线程池
@Configuration
@EnableAsync
public class ExecutorConfig {
private static final Logger logger = LoggerFactory.getLogger(ExecutorConfig.class);
@Bean
public Executor asyncServiceExecutor() {
logger.info("start asyncServiceExecutor");
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//配置核心线程数
executor.setCorePoolSize(5);
//配置最大线程数
executor.setMaxPoolSize(5);
//配置队列大小
executor.setQueueCapacity(99999);
//配置线程池中的线程的名称前缀
executor.setThreadNamePrefix("async-service-");
// rejection-policy:当pool已经达到max size的时候,如何处理新任务
// CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//执行初始化
executor.initialize();
return executor;
}
}
service层声明业务
@Override
@Async("asyncServiceExecutor")
public void executeAsync() {
logger.info("start executeAsync");
try{
Thread.sleep(1000);
}catch(Exception e){
e.printStackTrace();
}
logger.info("end executeAsync");
}