线程池的种类、创建方式
Executor:
执行器接口,利用Executor可以非显示的创建线程,调度任务和线程资源
ExecutorServer:
Executor的子接口,扩展了Executor接口,增加了又返回值的异步调用submit,增加了任务 停止方法等等
ScheduledExecutorService:
ExecutorServer的子接口,他提供了定时执行和延迟执行的功能
ThreadPoolExecutor(线程池的实现)
线程池的具体实现,它间接实现了ExecutorServer接口
ScheduledThreadPoolExecutor(线程池的实现)
线程池的具体实现,继承自ThreadPoolExecutor,实现了ScheduledExecutorService接口
ForkJoinPool(线程池的实现)
线程池的具体实现,它间接实现了ExecutorServer接口
Executors
线程池的工具类,通过Executors可以快捷的创建多种线程池
newFixedThreadPool:返回ExecutorService,固定线程数的线程池(最大、最小线程数都 是传入的参数)
newWorkStealingPool:返回ForkJoinPool,创建一个ForkJoinPool线程池
newSingleThreadExecutor:返回ThreadPoolExecutor,创建一个单个线程的线程池(顺序 执行时可以使用到)
newCachedThreadPool:返回ThreadPoolExecutor,创建一个核心线程数为0,最大线 程数时65535到线程池,如果线 程空闲超过60秒会被释放,谨慎使用。
newSingleThreadScheduledExecutor:返回ScheduledExecutorService,创建一个单线程 的定时任务线程池,添加任务时可 以指定延时执行时间以及定时触发参数
newScheduledThreadPool:返回ScheduledExecutorService,创建一个指定固定线程数的 线程池,添加任务时可以执行延时执行时间以及定时触发参数
unconfigurableExecutorService:返回ExecutorService
说到线程池,离不开线程池的参数,线程池的参数主要有如下
1:corePoolSize核心线程数
始终在运行的线程数,始终都有这些线程在运行,但是始终在运行的线程数并不保证是同样的 线程(这一点很重要)
2:maximumPoolSize最大线程数
同时运行的最大的线程数数量
3 BlockingQueue 阻塞队列
核心线程数已经达到配置值时,新进来的任务会进入到该队列中等待执行,因为是queue所以先进先出,队列里等待时间长的会先被执行
阻塞队列有:
ArrayBlockingQueue:有界队列,底层数据结构是数组
LinkedBlockingDeque:有界队列,如果不指定容量,容量为Integer.MAX_VALUE
SynchronousQueue:没有容量,不会存储任务信息,往队列中put任务时,如果没有执行线程做take操作,put会阻塞起来,直到有线程来获取任务
4: RejectedExecutionHandler 拒绝策略
如果阻塞队列已经达到最大值,无法在添加任务且同时运行的线程数达到了配置的最大线程数,此时会拒绝添加新的任务到队列中来
拒绝策略有4种
二:线程池运行核心原理
添加任务流程
线程运行完成之后会去等待队列里获取新的执行任务,执行任务之前会判断是否已经大于核心线程,如果大于核心线程,从queue中获取任务通过workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS),如果没有可执行的任务,获取超过了线程最长的生存时间改线程,会移除该工作线程
如果当前的工作线程数量<corePoolSize,则通过workQueue.take()获取任务,如果没有任务,则该线程一直阻塞在take()方法这里,知道拿到新的任务。
所有线程池里运行着的工作线程并不是固定不变的,可能会有更替的情况存在