线程池是什么?解决什么问题的?
管理线程的工具。
什么时候,什么场合才适合用。
昨天已经在AOP的时候有提出。
为什么要用这个东西?
为了解决不断地开启新线程的问题来使用。
如何使用,步骤和注意细项是什么。
使用方式一:
JDK直接提供。但是不复现实情况。
带缓存线程池 static ExecutorService newCachedThreadPool()
固定大小线程池 static ExecutorService newFixedThreadPool(int nThreads)
单线程线程池 static ExecutorService newSingleThreadExecutor()
自定义:
corePoolSize
,线程池中的核心线程数
maximumPoolSize
,线程池中的最大线程数
keepAliveTime
,空闲时间,当线程池数量超过核心线程数时,多余的空闲线程存活的时间,即:这些线程多久被销毁。
unit
,空闲时间的单位,可以是毫秒、秒、分钟、小时和天,等等
workQueue
,等待队列,线程池中的线程数超过核心线程数时,任务将放在等待队列,它是一个BlockingQueue
类型的对象
threadFactory
,线程工厂,我们可以使用它来创建一个线程
handler
,拒绝策略,当线程池和等待队列都满了之后,需要通过该对象的回调函数进行回调处理
缓冲队列BlockingQueue简介:
ArrayBlockingQueue
,队列是有界的,基于数组实现的阻塞队列
LinkedBlockingQueue
,队列可以有界,也可以无界。基于链表实现的阻塞队列
SynchronousQueue
,不存储元素的阻塞队列,每个插入操作必须等到另一个线程调用移除操作,否则插入操作将一直处于阻塞状态。该队列也是Executors.newCachedThreadPool()
的默认队列
PriorityBlockingQueue
,带优先级的无界阻塞队列
拒绝策略-handler
所谓拒绝策略,就是当线程池满了、队列也满了的时候,我们对任务采取的措施。或者丢弃、或者执行、或者其他...
jdk自带4种拒绝策略,我们来看看。
-
CallerRunsPolicy
// 在调用者线程执行 -
AbortPolicy
// 直接抛出RejectedExecutionException
异常 -
DiscardPolicy
// 任务直接丢弃,不做任何处理 -
DiscardOldestPolicy
// 丢弃队列里最旧的那个任务,再尝试执行当前
提交任务的几种方式
往线程池中提交任务,主要有两种方法,execute()
和submit()
。
execute()
用于提交不需要返回结果的任务,我们看一个例子。
submit()
用于提交一个需要返回果的任务。该方法返回一个Future
对象,通过调用这个对象的get()
方法,我们就能获得返回结果。
线程池监控
如果系统中大量用到了线程池,那么我们有必要对线程池进行监控。利用监控,我们能在问题出现前提前感知到,也可以根据监控信息来定位可能出现的问题。
那么我们可以监控哪些信息?又有哪些方法可用于我们的扩展支持呢?
首先,ThreadPoolExecutor
自带了一些方法。
-
long getTaskCount()
,获取已经执行或正在执行的任务数 -
long getCompletedTaskCount()
,获取已经执行的任务数 -
int getLargestPoolSize()
,获取线程池曾经创建过的最大线程数,根据这个参数,我们可以知道线程池是否满过 -
int getPoolSize()
,获取线程池线程数 -
int getActiveCount()
,获取活跃线程数(正在执行任务的线程数)
其次,ThreadPoolExecutor
留给我们自行处理的方法有3个,它在ThreadPoolExecutor
中为空实现(也就是什么都不做)。
-
protected void beforeExecute(Thread t, Runnable r)
// 任务执行前被调用 -
protected void afterExecute(Runnable r, Throwable t)
// 任务执行后被调用 -
protected void terminated()
// 线程池结束后被调用