只要是使用多线程,就必须要用线程池去管理。
1、线程池的作用(池化思想,数据库连接池)
线程创建是需要时间的,如果每次使用新线程的时候,都去创建线程,是比较耗时的。但是如果将线程先创建好,放到池子里面,用的时候直接从池子里面去取,就省略了创建线程的时间。(典型的用空间来换取时间)
架构调优的两种方案:
- 要么牺牲空间,来换取时间(池化思想,缓存)
- 要么牺牲时间,来换取空间
2、使用线程池的意义
①在架构方面,可以节省时间。
②在管理方面,通过线程池,可以规定线程的名字,我可以知道我这个线程池当中有哪些线程执行了哪些任务,通过日志可以快速定位问题。
通过观察日志输出,可以清楚的看到有显示线程的名字以及该线程执行的任务。
3、线程池的几个重要参数
在创建线程池的时候,要结合具体的业务,来规划这些参数。
最小线程数 1 :项目启动的时候,初始化的线程数。
核心线程数 4 :当线程池的线程都忙碌时,再进来新任务时,由最小线程数扩容到核心线程数。
只有一个线程a时,新任务进来,若a忙碌,则增加一个线程b,若a、b同时忙碌,再进来新任务时,增加线程c。
如果abcd四个线程都忙碌
队列大小 1000 :一般会设置的很大,当线程数达到核心线程数,再进来的任务就会进入到队列。
需要的线程数达到核心线程数后,再来的新任务就要加入到队列,队列先进先出。之前的任务执行完,先进队列的任务先进入线程池去执行。
最大线程数 8 :当核心线程数满了,当队列也满了,再来新任务,就会创建新线程来执行这个新任务,直到线程数达到最大线程数。
拒绝策略:如果说线程数达到最大线程数,并且队列也满了,就要执行拒绝策略。
拒绝策略有4种:
- 报错,告诉开发这个任务线程池执行不了,由开发来决定是否丢弃
- 丢弃当前任务
- 丢弃队列当中头结点的任务,最先进入队列的任务
- 由主线程去执行这个任务
一般情况下,前三种都会有丢弃任务的风险,但是性能都比较好,第4种最稳妥。
存活时间:当线程超过多长时间不执行任务,处于空闲状态,线程池会将它回收,直到数量达到核心线程数。
核心线程数:一般设置为cpu的核数
最大线程数:一般设置为cpu的核数 * 2
比如12核 24个线程
cpu的核数代表着同一时刻,多少个线程可以一起运行。涉及到时间片轮转算法。
8个线程 但是cpu只能同时调度4个线程 这4个线程会不断切换调度,是由转换时间的,但是特别块,我们是无感知的。
最先派给线程池的任务肯定最先执行?错误,所以说线程池不能保证顺序。
4、有界队列和无界队列
有界队列:有限制,这个队列最多可能容纳多少个,在创建队列的时候就规定好了。
无界队列:没有限制,来多少收多少。