1.什么是线程池?
讲故事:在Java世界里,线程池就像是一家忙碌的餐馆。有一天,餐馆老板决定要招聘一些服务员(线程),以应对日益增加的客流量(任务)。
老板开始筹划,他决定先设定一个最少必需的服务员人数(corePoolSize),确保餐馆不至于人手不足。然后,老板想了想,确定了一个最多可以雇佣的服务员上限(maximumPoolSize),以防突发繁忙的情况下可以应对。
餐馆里有个等候区(任务队列),客人来了先排队,服务员会从等候区找到任务处理。如果等候区满了(workQueue满了),新来的客人(新任务)可能会被告知稍等一会儿,或者老板会考虑雇佣更多服务员来处理。
还有一点很重要,如果有些服务员太久没事干(keepAliveTime时间到了),老板会决定解雇他们,毕竟长时间无事可做实在是太浪费了。(经典优化)
而当客流量激增,连餐馆都快不堪重负时,老板会选择一种拒绝策略(RejectedExecutionHandler),比如直接抛出异常(抱歉,今天餐馆爆满,我们已经招待不了更多客人了!)。
总之,好的线程池就像是一家经营有方的餐馆,合理调度服务员的数量和处理任务的速度,确保每一位客人都能在合理的时间内享受到优质的服务。记得,对待线程池就像对待点餐一样,量力而行,不要贪多哦!。
2.线程池的核心参数
在创建线程池时,可以配置以下核心参数:
核心线程数(corePoolSize):
这是线程池中保持的最小线程数,即使它们处于空闲状态也会保持存活。当有新任务提交时,线程池会优先创建这些核心线程来处理任务。
最大线程数(maximumPoolSize):
线程池允许创建的最大线程数。当任务队列已满且当前线程数小于最大线程数时,线程池会创建新线程来处理任务,直到达到最大线程数为止。
任务队列(workQueue):
用于保存等待执行的任务的队列。当线程池中的线程数达到核心线程数时,新任务会被放入任务队列中。Java提供了多种类型的任务队列,如LinkedBlockingQueue
、ArrayBlockingQueue
、SynchronousQueue
等,每种队列类型都有不同的特性适合不同的使用场景。
保持活动时间(keepAliveTime)和时间单位(unit):
当线程池中的线程数大于核心线程数时,这些多余的空闲线程在多长时间内会被销毁。keepAliveTime
指定了线程的存活时间,unit
指定了时间单位,例如秒、分钟等。
拒绝策略(RejectedExecutionHandler):
当任务提交给线程池被拒绝执行时的处理策略。常见的策略有:直接抛出异常、丢弃任务、丢弃最旧的任务、由提交任务的线程执行任务等。
线程工厂(threadFactory)
创建线程的工厂,可以设定线程名、线程编号等
(面试时候这几个回答会出来就已经可以,基本会再去问其他的了)
下面这段是ThreadPoolExecutor的部分源码