什么是线程池?
线程池是一种多线程的处理形式,处理过程中将任务提交到线程池中,任务的执行交由线程池来管理。
如果每个请求都创建一个线程,那么服务器的资源很快就会被消耗完,使用线程池可以减少创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。
为什么要使用线程池?
-
可以帮助我们管理线程,避免增加线程创建和销毁造成资源的消耗
-
提高响应速度
-
重复利用
线程池的创建
-
通过ThreadPoolExecutor()创建
-
里面的参数
-
corePoolSize:线程池核心线程最大值
-
maxiNumPoolSize:线程池最大线程数
-
keepAliveTime:线程池中非核心线程空闲的存活大小
-
unit:线程空闲存活时间单位
-
workQueue:存放任务的阻塞队列
-
threadFactory:设置创建线程的工厂
-
handler:线程池的饱和策略事件
-
线程池的任务执行
执行任务用的是execute();
-
提交一个任务,线程池里存活的线程数小于核心线程数,线程池会创建一个核心线程去执行此次任务
-
如果核心线程数满了,一个新提交的任务,则会放进任务队列workQueue排队等待执行
-
当线程池里面存活的线程数已经等于corePoolSize了,并且任务队列workQueue也满,判断线程数是否达到maximumPoolSize,即最大线程数是否已满,如果没到达,创建一个非核心线程执行提交的任务。
-
如果当前的线程数达到了maximumPoolSize,还有新的任务过来的话,直接采用拒绝策略处理。
四种拒绝策略
-
AbortPolicy(抛出异常)
-
DiscardPolicy(直接丢弃任务)
-
DiscardOldestPolicy(丢弃队列里最老的任务,讲这个任务继续提交到线程池)
-
CallerRunsPolicy(交给线程池调用所在的线程进行处理)
几种常见的线程池及使用场景
-
newSingleThreadExecutor
-
创建一个单线程化的线程池,只会用唯一的工作线程执行任务,保证所有的任务都能按照指定的顺序执行
-
核心线程数为1
-
最大线程数也为1
-
阻塞队列是LinkedBlockingQueue
-
keepAliveTime为0
-
-
newFixedThreadPool
-
创建一个定长线程,控制线程的最大并发数,超出的线程会在队列中等待
-
核心线程数和最大线程数大小一样
-
没有所谓的非空闲时间,即keepAliveTime为0
-
阻塞队列为无界队列LinkedBlockingQueue
-
提交任务
-
如果线程数少于核心线程,创建核心线程执行任务
-
如果线程数等于核心线程,把任务添加到LinkedBlockingQueue阻塞队列
-
如果线程执行完任务,去阻塞队列取任务,继续执行。
-
-
-
newCachedThreadPool
-
创建一个可缓存的线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回,则新建线程
-
核心线程数为0
-
最大线程数为Integer.MAX_VALUE
-
阻塞队列是SynchronousQueue
-
非核心线程空闲存活时间为60秒
-
提交任务
-
因为没有核心线程,所以任务直接加到SynchronousQueue队列。
-
判断是否有空闲线程,如果有,就去取出任务执行。
-
如果没有空闲线程,就新建一个线程执行。
-
执行完任务的线程,还可以存活60秒,如果在这期间,接到任务,可以继续活下去;否则,被销毁。
-
-
-
newScheduledThreadPool
-
创建一个定长线程池,支持定时及周期性执行任务
-
最大线程数为Integer.MAX_VALUE
-
阻塞队列是DelayedWorkQueue
-
keepAliveTime为0
-
scheduleAtFixedRate() :按某种速率周期执行
-
scheduleWithFixedDelay():在某个延迟后执行
-
添加一个任务
-
线程池中的线程从 DelayQueue 中取任务
-
线程从 DelayQueue 中获取 time 大于等于当前时间的task
-
执行完后修改这个 task 的 time 为下次被执行的时间
-
这个 task 放回DelayQueue队列中
-
-
execute和submit有啥区别?
-
execute和submit都用来提交所提交的任务
-
execute适用于不用关注返回值的场景,只需要将线程丢到线程池中执行。
-
submit方法适用于关注有返回值的场景
线程池有那些工作队列?
-
ArrayBlockingQueue 基于数组的有界阻塞队列
-
LinkedBlockingQueue 基于链表结构的阻塞队列
-
SynchronousQueus 不存储元素的阻塞队列
-
PriorityBlockingQueue 优先级的无限阻塞队列
处理线程池异常
-
在任务代码try /catch 捕捉异常
-
通过Future对象的get方法接收抛出的异常
-
为工作者线程设置UncaughtExceptionHandler,在uncaughtException方法中处理异常
-
重写ThreadPoolExecutor的afterExecute方法,处理传递的异常引用