
一、为什么需要线程池在介绍之前我们先说一下为什么要有线程池在没有线程池之前我们通常要通过new Thread手动创建线程池并发布任务但这种方式存在弊端所以我们需要线程池来实现线程复用的作用我们需要提前创建一批线程放入池中任务到达时刻直接用空闲的线程结束后线程不销毁等待下一个任务。二、线程池的七个核心参数线程池的行为由以下七个参数共同决定1.corePoolsize核心线程数线程池中始终存活的线程数量即使空闲也不会被销毁2.maximumPoolSIze (最大线程数)线程池允许创建的最大线程数量包含核心线程和非核心线程。3.keepAliveTime非核心线程线程存活时间非核心线程空闲超过此时间后会被销毁回收。4.TimeUnit(时间单位)空闲时间的单位,秒、毫秒等。5.BlockingQueue(阻塞工作队列)当核心线程都在忙时新任务会放入此队列中排队等待。6.ThreadFactory(线程工厂)用于创建线程可以自定义线程名、优先级等。7.RejectedExecutionHandler(拒绝策略)当线程池和队列都满了无法处理新任务时采取的处理策略。四个拒绝策略AbortPolicy直接抛出 RejectedExecutionException 异常默认DiscardPolicy直接丢弃任务不抛异常DiscardOldestPolicy丢弃队列队头最老任务尝试执行当前新任务CallerRunsPolicy由提交任务的调用者线程执行该任务三、线程池的执行流程调用execute( )提交线程任务线程池按如下逻辑处理任务1.判断当前运行的工作线程数是否小于核心线程数如果未超出直接创建核心线程进行执行任务。2.若核心线程数已满则线程池会将任务放入工作队列若工作队列未满则在工作队列中排队等待直到有核心线程空闲再从队列中取出线程任务。3.若任务队列已满判断当前工作线程数是否小于最大线程数若未超出则创建非核心线程去执行任务。4.如果已经达到最大线程数没有多余线程、队列也存不下任务触发拒绝策略处理新提交的任务。四、Executors创建的三种常见线程池1.newFixedThreadPool ( )固定数量的线程池核心线程数 最大线程数没有非核心线程使用无界阻塞队列LinkedBlockingQueue。意味着它的线程数量固定如果任务队列足够长就不会创建非核心线程。所有线程都是核心线程空闲不会回收任务过多全部堆积在队列任务量过大可能耗尽内存。适合任务量比较稳定的场景。2.newCachedThreadPool( )动态数量的线程池核心线程数为 0最大线程数为 Integer.MAX_VALUE所有的线程都是非核心线程非核心线程数会随着任务的增多而增多随任务的减少而减少。空闲存活时间默认 60 秒非核心线程空闲超过 60 秒没有新任务就会被销毁用于节省资源。使用 SynchronousQueue 队列队列不存储任务任务到来直接新建线程。适合大量短时间执行的任务。3.newSingleThreadExecutor( )单线程的线程池该线程池只有一个核心线程最大线程数也是 1多余的任务会在无界工作队列中排队等待。所有任务串行执行保证任务按提交顺序执行线程异常终止会自动重建一个新线程继续工作。适合需要顺序执行任务的场景。五、线程池的关闭shutdown( ):平缓关闭不再接收新任务已经提交的任务继续执行完毕。shutdownNow( 强制关闭尝试中断正在执行的任务返回队列中未执行的任务列表。