前言:线程池存在的意义
- java面向多线程编程时,线程创建过多,容易引发内存溢出。
- Java线程的创建、销毁和线程间切换是一件比较耗费计算机资源的。如果我们需要用多线程处理任务,并频繁的创建、销毁线程会造成计算机资源的无端浪费,因此项目中会使用是线程池技术。
线程池详解
线程池的优势
- 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
- 提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
- 提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,可能也会导致内存占用过多而产生OOM。
- 什么是OOM
程序申请内存过大,虚拟机无法满足我们,然后自杀了。这个现象通常出现在大图片的APP开发,或者需要用到很多图片的时候。通俗来讲就是我们的APP需要申请一块内存来存放图片的时候,系统认为我们的程序需要的内存过大,及时系统有充分的内存,比如1G,但是系统也不会分配给我们的APP,故而抛出OOM异常,程序没有捕捉异常,故而弹窗崩溃了 - 为什么会有OOM?
内存泄露:申请使用完的内存没有释放,导致虚拟机不能再次使用该内存,此时这段内存就泄露了,因为申请者不用了,而又不能被虚拟机分配给别人用。(应用用的太多,并且用完没释放,浪费了。此时就会造成内存泄露或者内存溢出。) 内存溢出:申请的内存超出了JVM能提供的内存大小,此时称之为溢出。(分配的少了:比如虚拟机本身可使用的内存(一般通过启动时的VM参数指定)太少。)
线程池的结构
线程池的工作原理
线程池生命周期
- 首先来分析源码
(线程池的状态)
状态 | 含义 | 值 | 说明 |
---|
状态 value 说明 | | | | RUNNING | 当线程池创建出来的初始状态 | 111 | 能接受任务,能执行阻塞任务,能执行正在执行的任务 | SHUTDOWN | 调用shutdown方法 | 000 | 不接受新任务,能执行阻塞任务 ,能执行正在执行的任务 | STOP | 调用shutDownNow | 001 | 不接受新任务,打断正在执行的任务,丢弃阻塞任务 | TIDYING | 中间状态) | 010 | 任务全部执行完,活动线程也没了 | TERMINATED | (终结状态 | 011 | 线程池终结 |
几种状态之间的转化过程
-
解释含义
- 线程池在构造前(new操作)是初始状态,一旦构造完成线程池就进入了执行状态RUNNING。
严格意义上讲线程池构造完成后并没有线程被立即启动,只有进行“预启动”或者接收到任务的时候才会启动线程。但是线程池是出于运行状态,随时准备接受任务来执行。
具体转化状态方法
API
调用shundown() 方法线程池的状态由 RUNNING——>SHUTDOWN
调用shutdowNow() 方法线程池的状态由RUNNING——>STOP
当任务队列和线程池均为空的时候 线程池的状态由STOP/SHUTDOWN——–>TIDYING
当terminated() 方法被调用完成之后,线程池的状态由TIDYING———->TERMINATED状态
线程池的几个主要参数
参数名称 | 翻译 | 解释 |
---|
corePoolSize | 核心线程池大小) | 核心线程池大小, 新的任务到线程池后,若线程池已创建的线程数小于corePoolSize,即便存在空闲线程,线程池会创建新的线程,直到核心线程池已满。 | maximumPoolSize | 最大线程池大小 | 线程池所允许的最大线程个数。当队列满了,且已创建的线程数小于maximumPoolSize,则线程池会创建新的线程来执行任务。另外,对于无界队列,可忽略该参数。 | keepAliveTime | 线程保持存活时间 | 当线程池中线程数大于核心线程数时,线程的空闲时间如果超过线程存活时间,那么这个线程就会被销毁,直到线程池中的线程数小于等于核心线程数。 | unit | 参数的时间单位 | 线程存活时间的单位 | workQueue | 任务队列 | 用于传输和保存等待执行任务的阻塞队列。 | threadFactory | 线程工厂 | 创建新线程。主要用于给任务线程起个自定义名字 | handler | 线程饱和策略 | 当线程池和队列都满了,再加入线程时会执行此策略。 |
Executors类提供的线程池构造方法
- newCachedThreadPool
- newFixedThreadPool
- newScheduledThreadPool
- newSingleThreadExecutor
|