浅析java线程池

---- 此文来自某位渣男  他说:核心线程永不销毁     https://blog.csdn.net/weixin_35722483/article/details/123367288?spm=1001.2014.3001.5502

Java线程池
1. 常见的四大线程池
Executors.newSingleThreadExecutor();
Executors.newFixedThreadPool();
Executors.newScheduledThreadPool();
Executors.newCachedThreadPool();


2. ThreadPoolExecutor的七大参数
Int corePoolSize
核心线程数
int maximumPoolSize
最大线程数(线程池中,最多存在多少个线程)
long keepAliveTime
保持活跃的时间(在指定时间内,如果没有任务,释放非核心线程)
TimeUnit unit
时间单位(参数TimeUnit中的常量)
BlockingQueue<Runnable> workQueue
等待队列
ThreadFactory threadFactory
创建线程的工厂
RejectedExectuionHandler handler
拒绝策略


3. java四大线池程本质
java线程池本质上只有一个。
无论哪个线程池,都是调用ThreadPoolExecutor创建出来的。
线程池有不同的特性,是因为创建线程池的时候,参数不一样。
3.1 Executors.newSingleThreadExecutor简单线程池
​ 调用ThreadPoolExecutor构造函数时的七个参数值。

参数含义 参数名称 参数类型 取值 备注
核心线程 corePoolSize int 1 核心线程数为有且只有一个
最大线程 maxNumPoolSize int 1 最大线程数量只能存在一个
存活时间 keepAliveTime long 0L 线程保持活跃时间长度,加上时间单位计时
时间单位 unit TimeUnit TimeUnit.MILLISECONDS 参数TimeUnit中的常量
等待队列 workQueue BlockingQueue<Runnable> LinkedBlockingQueue<Runnable> 等待队列长度为Integer.MAX_VALUE(int最大值)
有且只有一个线程工作,队列无穷大,所有的任务,都交个这个线程来处理,不论任务多少,使用线程池中的唯一线程,依次的执行队列中的任务。

当核心线程数和最大线程数相等的时候,保持活跃的时间设置是没有意义的,因为核心线程不会被释放,最大线程数不会超过核心线程数,所以当任务执行完成之后,不会进行线程释放

等待队列 new LinkedBlockingQueue<Runnable>() 无界队列,构造方法中的初始长度为Integer.MAX_VALUE(int最大值)

等待队列无穷大,意味着该线程池时没有拒绝策略

/**
* Creates a {@code LinkedBlockingQueue} with a capacity of
* {@link Integer#MAX_VALUE}.
*/
public LinkedBlockingQueue() {
this(Integer.MAX_VALUE);
}

3.2 Executors.newFixedThreadPool固定线程池
​ 调用ThreadPoolExecutor构造函数时的七个参数值,在创建这个线程池的时候,需要指定一个参数,该参数指定的是核心线程数和最大线程数

​ Executors.newFixedThreadPool(int size)

参数含义 参数名称 参数类型 取值 备注
核心线程 corePoolSize int size size由调用方法时,指定的数量决定
最大线程 maxNumPoolSize int size size由调用方法时,指定的数量决定
存活时间 keepAliveTime long 0L 线程保持活跃时间长度,加上时间单位计时
时间单位 unit TimeUnit TimeUnit.MILLISECONDS 参数TimeUnit中的常量
等待队列 workQueue BlockingQueue<Runnable> LinkedBlockingQueue<Runnable> 等待队列长度为Integer.MAX_VALUE(int最大值)
和newSingleThreadExecutor的区别在于,创建线程池时,需要指定一个数量size,size在其内部调用ThreadPoolExecutor构造方法时,作为核心线程数和最大线程数[同样导致活跃时间无效],等待队列也是无穷大

Executors.newFixedThreadPool和newSingleThreadExecutor的唯一区别就是需要指定一个线程数量

3.3 Executors.newScheduledThreadPool 安排
​ 调用ThreadPoolExecutor构造函数时的七个参数值,在创建这个线程池的时候,需要指定一个参数,该参数指定的是核心线程数

​ Executors.newScheduledThreadPool(int corePoolSize)

参数含义 参数名称 参数类型 取值 备注
核心线程 corePoolSize int size size由调用方法时,指定的数量决定
最大线程 maxNumPoolSize int Integer.MAX_VALUE 等于无穷大
存活时间 keepAliveTime long 0L 线程保持活跃时间长度,加上时间单位计时
时间单位 unit TimeUnit NANOSECONDS 参数TimeUnit中的常量
等待队列 workQueue BlockingQueue<Runnable> new DelayedWorkQueue() 该队列的作用:队列中有等待任务,直接创建新线程
当前线程池,只指定一个初始化的核心线程数,等待队列相当于没有缓存机制,进入队列的任务会立刻创建新的线程来执行任务,由于线程保持存活的时间为0所以,超过核心线程数的线程在执行完任务后,会被释放

当达到核心线程数满了以后,就会创建新的线程,当新开出的线程,在完成任务之后,就会被直接销毁。当前线程池在理论上可以创建无穷个线程

DelayedWorkQueue 队列初始化的时候,长度为0,队列不缓存任务,入队列即刻出队列

3.4 Executors.newCachedThreadPool 缓存
​ 调用ThreadPoolExecutor构造函数时的七个参数值

​ Executors.newCachedThreadPool()

参数含义 参数名称 参数类型 取值 备注
核心线程 corePoolSize int 0 核心线程为0
最大线程 maxNumPoolSize int Integer.MAX_VALUE 等于无穷大
存活时间 keepAliveTime long 60L [一分钟] 线程保持活跃时间长度,加上时间单位计时
时间单位 unit TimeUnit TimeUnit.SECONDS 参数TimeUnit中的常量
等待队列 workQueue BlockingQueue<Runnable> SynchronousQueue<Runnable> 该队列的作用:队列中有等待任务,直接创建新线程
当前线程池,没有核心线程数量,有任务的时候,启动线程,在线程任务完成之后,等待60秒,在此期间如果有新的任务,复用线程,如果没有新的任务,超过线程存活时间60秒,则销毁线程

 

4. 线程池的作用
​ 创建线程消耗的性能消耗比较大,将创建的线程存放起来,在线程执行后,不释放。线程的复用性提高,多任务的时候,其中一个线程执行完毕后,可以直接接受下一个任务,避免了创建线程的性能和时间消耗。

​ 不用每次执行任务的时候,都需要创建线程,线程可以复用的情况下,直接从线程池中获取线程,在线程完成任务后,不被释放,可以接受下一次任务。

​ 举例,一个银行平时只开三个窗口(核心线程数),某天业务量爆发,需要办理业务的人增多。三个窗口每个窗口每次只能帮一个人办理业务,很多人都只能在大厅等待(等待队列),如果大厅坐满了等待的人,银行会觉得需要办理业务的人太多了,于是会多开几个窗口,但不能大于银行本身的窗口最大数,当银行开启了足够多的窗口之后,大厅的人数开始减少。

​ 当大厅左右人都办理完业务离开两分钟之后(保持的活跃时间,时间单位),后开的那些窗口的任务完成了,就会将窗口关闭。

​ 另一种情况,线程池中的所有线程全部处在执行任务的状态。银行所有的窗口,都在处理业务,大厅的人没有减少,反而还在增加,这种情况下,银行需要告知后面来的人,需要换个时间再来办理,在线程池中是拒绝策略。

5. 自定义线程池
使用ThreadPoolExecutor自定义线程池。

线程池在刚创建出来的时候,里面是没有线程的。

在我们向线程池提交任务的时候,线程池才会开始创建线程。

如果核心线程数是10,最大的线程数是20,当我们提交第11个的时候(前十个没有结束),线程池会创建新的线程吗?

线程池创建线程的策略,先把核心线程数填满,然后填满等待队列,等待队列如果满了,就创建新的线程,但是总线程数不能大于最大线程数。

 

6. 线程池常见问题
线程池刚创建的的时候,内部存在几个线程?
线程池在刚创建的时候,内部没有线程
线程池在创建之后,什么时候才会产生线程?
在程序运行过程中,向线程池提交任务的时候,线程池才会创建线程
如果核心线程数是10,最大线程数是20,当提交第11个任务是(前10个线程执行未结束),线程池会不会创建新的线程?
不会,线程池创建线程的策略,先把核心线程数填满,然后填满等待队列,等待队列如果满了,就创建新的线程,总线程数不能大于最大线程数
 

posted @ 2022-03-10 14:23  chdchd  阅读(73)  评论(0编辑  收藏  举报