面试官如果我一直往线程池里面放任务会发生什么,线程池并发面试题
面试官:线程池的工作原理是啥?能手写一个线程池吗?为什么要有线程池这个东西?创建线程对象不像其他对象一样在JVM分配内存即可,还要调用操作系统内核的API,然后操作系统为线程分配一系列的资源,这个成本就很高了。所以线程是一个重量级对象,应该避免频繁创建和销毁再说一下线程池的大概工作流程以前我们运行线程的时候new Thread().start()即可,如果线程数多了,频繁的创建线程和销毁线程很费时间。
然后Doug Lea就这样设计了一下,
对线程池的原理不太了解的,可以看一下这篇文章
面试官:线程池的工作原理是啥?能手写一个线程池吗?
为什么要有线程池这个东西?创建线程对象不像其他对象一样在JVM分配内存即可,还要调用操作系统内核的API,然后操作系统为线程分配一系列的资源,这个成本就很高了。所以线程是一个重量级对象,应该避免频繁创建和销毁
再说一下线程池的大概工作流程以前我们运行线程的时候new Thread().start()即可,如果线程数多了,频繁的创建线程和销毁线程很费时间。
然后Doug Lea就这样设计了一下,预先启动几个线程,还准备好一个容器。每次想执行任务时,就将实现了Runnable接口的任务放到这个容器中,预先启动好的线程不断从容器中拿出任务,调用执行Runnable接口的run方法,这样刚开始启动的线程就能执行很多次任务。大概流程就是这样,真正的线程池考虑的东西比较多。
想到没有,这就是典型的生产者-消费者模式,线程池的使用者是生产者,线程池本身是消费者。用代码来实现一下
各种参数来看一下Java中的线程池类ThreadPoolExecutor的构造函数有哪些参数?
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler)来类比学习一下这些参数,我们把线程池类比为项目组,线程是这个公司的成员
corePoolSize:线程池中最少的线程数,一个项目组总得有corePoolSize人坚守阵地,都是签订劳动合同了,不能随便撤。
maximumPoolSize:当项目很忙时,就得加人,请其他项目组的人来帮忙。但是公司空间有限,最多只能加到maximumPoolSize个人。当项目闲了,就得撤人了,最多能撤到corePoolSize个人
keepAliveTime & unit:上面提到项目根据忙闲来增减人员,那在编程世界里,如何定义忙和闲呢?如果一个线程在keepAliveTime(时间数字)* unit(时间单位)时间内都没有执行任务,说明这个线程很闲。如果此时线程数大于corePoolSize,这个线程就要被回收了
workQueue:就是任务队列
threadFactory:自定义如果创建线程,例如给线程指定一个有意义的名字
handler:workQueue满了(排期满了),再提交任务,该怎么处理呢?这个就是处理策略,线程池提供了4种策略,你也可以实现RejectedExecutionHandler接口来自定义策略
执行流程
1.线程池刚创建时,里面没有一个线程。任务队列是作为参数传进来的。不过,就算队列里面有任务,线程池也不会马上执行他们。
2.当调用execute()方法添加一个任务时,线程池会做如下判断:
a)如果正在运行的线程数量小于corePoolSize,那么马上创建线程运行这个任务
b)如果正在运行的线程数量大于或等于corePoolSize,那么将这个任务放入队列
c)如果这时候队列满了,而且正在运行的线程数量小于maximunPoolSize,那么还是要创建非核心线程立刻运行这个任务
d)如果队列满了,而且正在运行的线程数量大于或等于maximunPoolSize,那么线程池会抛出RejectedExecutionException
3.当一个线程完成任务时,它会从队列中取下一个任务来执行
4.当一个线程无事可做,超过一定的时间(keepAliveTime)时,线程池会判断,如果当前运行的线程数大于corePoolSize,那么这个线程就被停掉。所以线程池的所有任务完成后,它最终会收缩到corePoolSize的大小
可以用如下图来表示整体流程
文章评论