线程池:用于管理线程的工具,本质上使用计算机内存加快程序处理速度,因为JVM每次新建一个线程的时候,都会在操作系统内部占用占用一个操作系统内存
优点:
-
降低资源消耗。通过重复利用已创建的线程,降低线程创建和销毁造成的消耗。
-
提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
-
增加线程的可管理型。线程是稀缺资源,使用线程池可以进行统一分配,调优和监控。
核心属性:
threadFactory(线程工厂):用于创建工作线程的工厂
corePoolSize(核心线程数):当线程池运行的线程少于 corePoolSize 时,将创建一个新线程来处理请求,即使其他工作线程处于空闲状态
workQueue(队列):用于保留任务并移交给工作线程的阻塞队列
maximumPoolSize(最大线程数):线程池允许开启的最大线程数
handler(拒绝策略):往线程池添加任务时,将在下面两种情况触发拒绝策略:1)线程池运行状态不是 RUNNING;2)线程池已经达到最大线程数,并且阻塞队列已满时
keepAliveTime(保持存活时间):如果线程池当前线程数超过 corePoolSize,则多余的线程空闲时间超过 keepAliveTime 时会被终止
工作原理
任务队列:
1.ArrayBlockingQueue:一个由数组结构组成的有界阻塞队列(数组结构可配合指针实现一个环形队列)
2.LinkedBlockingQueue: 一个由链表结构组成的有界阻塞队列,在未指明容量时,容量默认为 Integer.MAX_VALUE
3.PriorityBlockingQueue: 一个支持优先级排序的无界阻塞队列,对元素没有要求,可以实现 Comparable 接口也可以提供 Comparator 来对队列中的元素进行比较。跟时间没有任何关系,仅仅是按照优先级取任务
4.DelayQueue:类似于PriorityBlockingQueue,是二叉堆实现的无界优先级阻塞队列。要求元素都实现 Delayed 接口,通过执行时延从队列中提取任务,时间没到任务取不出来。
5.SynchronousQueue: 一个不存储元素的阻塞队列,消费者线程调用 take() 方法的时候就会发生阻塞,直到有一个生产者线程生产了一个元素,消费者线程就可以拿到这个元素并返回;生产者线程调用 put() 方法的时候也会发生阻塞,直到有一个消费者线程消费了一个元素,生产者才会返回
6.LinkedBlockingDeque: 使用双向队列实现的有界双端阻塞队列。双端意味着可以像普通队列一样 FIFO(先进先出),也可以像栈一样 FILO(先进后出)
7.LinkedTransferQueue: 它是ConcurrentLinkedQueue、LinkedBlockingQueue 和 SynchronousQueue 的结合体,但是把它用在 ThreadPoolExecutor 中,和 LinkedBlockingQueue 行为一致,但是是无界的阻塞队列
拒绝策略:
1.AbortPolicy(默认):丢弃任务并抛出 RejectedExecutionException 异常
2.CallerRunsPolicy:由调用线程处理该任务
3.DiscardPolicy:丢弃任务,但是不抛出异常。可以配合这种模式进行自定义的处理方式
4.DiscardOldestPolicy:丢弃队列最早的未处理任务,然后重新尝试执行任务
4种功能线程池:
1.FixedThreadPool:定长线程池,只有核心线程,线程数量可以自己设定(固定),能控制线程最大并发数
2.ScheduledThreadPool: 定时线程池,核心线程数量固定,非核心线程量无限,执行完闲置10ms自动回收,适合定时任务或者周期任务
3.CachedThreadPool:缓存线程池,无核心线程,非核心线程数量无限,执行完闲置60s后自动回收,适合执行大批量且耗时短的任务
4.SingleThreadExecutor:单线程化线程池,只有一个核心线程,无非核心线程,执行完立刻回收,适合单线程操作任务
在JDK帮助文档中,有如此一段话:
“强烈建议程序员使用较为方便的Executors
工厂方法Executors.newCachedThreadPool()
(缓存线程池,可以进行自动线程回收)、Executors.newFixedThreadPool(int)
(定长线程池)Executors.newSingleThreadExecutor()
(单线程化线程池)
弊端:
FixedThreadPool和SingleThreadExecutor堆积的请求队列都采用LinkedBlockingQueue,可能会导致OOM(耗费大量内存)
ScheduledThreadPool和CachedThreadPool由于非核心线程数量无限,很容易创造出很多线程,导致OOM(耗费大量内存)