一、前言

大家在面试过程中,必不可少的问题是线程池,小编也是在面试中被问啥傻了,JUC就了解的不多。加上做系统时,很少遇到,自己也是一知半解,最近看了尚硅谷阳哥的课,恍然大悟,特写此文章记录一下!如果还不了解线程池的小伙伴,一定要认真看完,你会有收获的哈!!

二、线程池创建使用

答:使用Executors看一下源码是有好多个,经常用的也就三个,今天就展示靠上的五种。

//创建一个定长线程池,超出的线程会在队列中等待
ExecutorService executorService = Executors.newFixedThreadPool(5);
//创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,
ExecutorService executorService1 = Executors.newSingleThreadExecutor();
//创建一个可缓存线程池,可以自动扩容,扩容大小为int最大值,因为太大可以直接理解为无限大
ExecutorService executorService2 = Executors.newCachedThreadPool();
//创建一个定长线程池,该线程池可以安排命令在给定延迟后运行,或定期执行。
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);
//1.8新增-创建一个带并行级别的线程池,并行级别决定了同一时刻最多有多少个线程在执行,不传参数默认为CPU个数
// Runtime.getRuntime().availableProcessors()查看本机CPU个数
ExecutorService executorService3 = Executors.newWorkStealingPool();

三、线程池的核心参数

//创建线程池,底层代码
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler) {
    if (corePoolSize < 0 ||
        maximumPoolSize <= 0 ||
        maximumPoolSize < corePoolSize ||
        keepAliveTime < 0)
        throw new IllegalArgumentException();
    if (workQueue == null || threadFactory == null || handler == null)
        throw new NullPointerException();
    this.corePoolSize = corePoolSize;
    this.maximumPoolSize = maximumPoolSize;
    this.workQueue = workQueue;
    this.keepAliveTime = unit.toNanos(keepAliveTime);
    this.threadFactory = threadFactory;
    this.handler = handler;
}

1. corePoolSize:线程池中的核心线程数,核心线程会一直存在,即使没有任务执行。
2. maximumPoolSize:线程池能够容纳同时执行的最大线程数,此值必须大于等于1
3. keepAliveTime:当线程数大于核心数时,这是多余空闲线程在终止前等待新任务的最长时间。(意思就是本来核心线程三个,已占满,扩展到最大线程数到5,解决完后没有线程任务了,这时设置一个时间,过了这个时间被扩展的2个非核心线程会被回收)
4. unit:keepAliveTime的时间单位。
5. workQueue:任务队列,被提交但尚未被执行的任务,相当于去饭店吃饭,餐桌满了,要在外边排队(阻塞队列)
6. threadFactory:表示生成线程池中工作线程的线程工厂,用于创建线程一般用默认的即可。
7. handler:拒绝策略,表示当队列满了并且工作线程大于等于线程池的最大线程数。

四、线程池的底层工作原理

- 主要处理流程图(来源百度)
在这里插入图片描述
- 底层工作原理图(来源尚硅谷阳哥)
在这里插入图片描述
- 流程梳理

1. 在创建了线程池后,等待提交过来的任务请求。
2. 当调用execute()方法添加一个请求任务时,线程池会做如下判断:
2.1 如果正在运行的线程数量小于corePoolSize,那么马上创建线程运行这个任务;
2.2 如果正在运行的线程数量大于或等于corePoolSize,那么将这个任务放入队列;
2.3 如果这时候队列满了且正在运行的线程数量还小于maximumPoolSize,那么还是要创建非核心线程立刻运行这个任务;
2.4 如果队列满了且正在运行的线程数量大于或等于maximumPoolSize,那么线程池会启动饱和拒绝策略来执行。
3.当一个线程完成任务时,它会从队列中取下一个任务来执行。
4.当一个线程无事可做超过一定的时间(keepAliveTime)时,线程池会判断:
如果当前运行的线程数大于corePoolSize,那么这个线程就被停掉;所以线程池的所有任务完成后它最终会收缩到corePoolSize 的大小。

五、总结

这样就理解很透彻了,反击尚硅谷阳哥的课程。打广告时间到了,欢迎访问小王博客站,如果你也有自己的网站留言一起做个友联!

小王博客站

Q.E.D.