线程池的作用是什么?
- 线程池的主要作用可以复用线程资源,方便管理,对开发者来说提供了很便利的代码,通过复用线程降低资源消耗,提高线程的可管理性,更易于开发者使用,所以项目中用线程池比较多
线程池的实现方式有哪些种类
-
ScheduledThreadPool(定时线程池):线程池用于执行定时任务和周期性任务。可以指定核心线程数,以及是否支持核心线程数以外的线程执行任务
-
SingleThreadExecutor(单线程线程池):线程池只有一个核心线程,确保所有任务按照指定顺序执行
-
FixedThreadPool(定长线程池):线程池的核心线程数和最大线程数是固定的
-
CachedThreadPoo(可缓存线程):线程池的核心线程数为0,最大线程数为Integer.MAX_VALUE,当有新任务提交时,会尝试复用已有线程执行任务,如果没有可用的线程,则创建新线程执行任务。空闲线程会在60秒后被销毁。
线程池的原理是什么?
线程池的原理在于7个核心参数
-
corePoolSize(核心线程数):线程池维护线程的最少线程数量
-
maximumPoolSize(最大线程数):线程池所能容纳的最大线程数,当活跃线程数达到该数值后,后续的新任务将会阻塞。
-
keepAliveTime(空闲线程存活时间):线程池中的线程数量超过核心线程数,空闲一段时间后如果超过该时长,非核心线程就会被回收。
-
Timeunit(时间单位):空闲线程活动保持时间
-
workQueue(任务队列):线程池所使用的任务缓冲队列,通过线程池的 execute() 方法提交的Runnable对象将存储在该参数中,其采用阻塞队列实现。
-
threadFactory(线程工厂):为线程池创建新线程
-
handler(拒绝策略):线程池对拒绝任务的处理策略,当达到最大线程数时需要执行的饱和策略
线程池工作原理
- 首先创建线程池的时候并不会创建线程出来,而是在提交任务的时候才会创建线程,在提交任务的时候会判断当前线程池中的线程个数是不是小于核心线程数,如果小于就创建线程并执行所提交的任务,如果不小于就将任务添加到阻塞队列中去,等待工作线程获取执行 ,如果阻塞队列也满了,表示任务太多了,就会新增一个线程资源执行这个多余的任务,执行完了就会自己消亡,但是新增线程不能大于最大线程数,如果队列也放不下,线程也不能新增了,就会执行拒绝策略
线程池任务结束后会不会回收线程?
- 程池中的线程在执行完任务后,会继续等待队列中的新任务。如果在一定时间内没有新任务到达,线程池中的线程可能会根据具体的实现机制进行一定的空闲线程回收
线程池复用的原理?
-
线程池的复用关键在于 Worker工作线程这个角色,在线程池中,Worker 是执行任务的实际工作者,它包含一个线程对象和一个任务对象(通过 Runnable 实现)。当向线程池提交任务后,线程池会在内部将任务封装为一个 Worker,并将其放入线程池中进行执行,Worker线程会调用其线程对象的 start 方法,从而运行 Worker 的 run 方法。在run方法中,Worker 会通过循环不断地从任务队列中获取任务并执行。如果当前没有待执行的任务,则会等待(block),直到队列中有新的任务到来。
-
核心点就在于Worker线程一旦完成了当前任务的执行,它并不会销毁,而是会继续等待队列中的新任务到来。这样做的好处是避免了频繁地创建和销毁线程,提高了性能和效率。
线程池的拒绝策略有哪些?如何选择合适的拒绝策略?
-
AbortPolicy(默认策略):当线程池无法处理新提交的任务时,会抛出 RejectedExecutionException 异常,中止执行。
-
CallerRunsPolicy:当线程池的队列已满且无法接收新任务时,会将该任务交给提交任务的线程执行,而不会开启新的线程
-
DiscardPolicy:当线程池无法处理新提交的任务时,会丢弃该任务不抛出异常,线程队列已满的情况下,后进来的任务都丢弃。
-
DiscardOldestPolicy:线程池无法处理新提交的任务时,会丢弃队列中最早的一个任务,然后重新提交被拒绝的任务。
如何正确关闭线程池?
- 调用线程池的shutdown()方法,这个方法会平缓地关闭线程池,不再接受新的任务,但会等待已提交的任务执行完成。