## 介绍
经常会使用线程来处理异步任务,但是每个线程的创建和销毁都是有一定的开销,如果每次执行一个任务都需要开一个新的线程去执行,则这些线程创建和销毁将消耗大量的资源,并且很难控制。
Java 提供了 Executor 框架用于把任务的提交和执行解耦,任务的提交交给 Runnable 或者 Callable,而 Executor 用来处理任务,Executor 框架用来处理任务。Executor 框架中最核心的成员就是 ThreadPoolExecutor ,它是线程池的核心实现类。
## ThreadPoolExecutor
可以通过 ThreadPoolExecutor 来创建一个线程池,ThreadPoolExecutor 类一共有四个构造方法,其中拥有最多参数的构造方法:
```java
public ThreadPoolExecutor(
int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
```
- corePoolSize 核心线程数,默认情况下线程池是空的,只有任务提交时才会创建线程。如果当前运行的线程数少于 corePoolSize,则创建新线程来处理任务;如果等于或者大于 corePoolSize ,则不再创建新线程。如果调用线程池的 prestartAllcoreThread方法,则线程池会提前创建并启动所有的核心线程来等待任务。
- maximumPoolSize:线程池允许创建的最大线程数。如果任务队列满了并且线程数小于 maximumPoolSize ,则线程池仍会创建新的线程来处理任务。
- keepAliveTime 非核心线程闲置的超时时间,超过这个时间则回收。如果任务很多,并且每个任务的执行时间很短,则可以调大 keepAliveTime 来提高线程的利用率。另外如果设置 allowCoreThreadTimeOut 为 true,keepAliveTime 也会应用到核心线程上。
- unit keepAliveTime的时间单位。
- workQueue 任务队列,如果当前的线程数大于 corePoolSize,则将任务添加到此任务队列中。该任务队列是 BlockindQueue (阻塞队列)类型的。
- threadFactory 线程工厂,可以用线程工厂给每个创建出来的线程设置名字,一般情况下不需要设置该参数
- handler 饱和策略,这是当前任务队列和线程池都满的时候采取的应对策略,默认是 AbordPolicy,表示无法处理新任务,并抛出 RejectExecutionException 异常,共四种策略,分别如下:
1. AbortPolicy(默认) : 抛出异常,并删除任务。
2. CallerRunsPolicy:用调用者所在的线程处理任务,此策略提供简单的反馈控制机制,能够减缓新任务的提交速度。
3. DiscardPolicy:不执行任务,并将该任务删除
4. DiscardOldestPolicy :会抛弃任务队列中最旧的任务也就是最先加入队列的,再把这个新任务添加进去。
流程图:
![](https://markdown-1258186581.cos.ap-shanghai.myqcloud.com/20190610224214.png)
## 四种常见的线程池:
### 1、FixedThreadPool
可重用的固定线程数量的线程池。核心数量和最大数量一致。
```java
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
```
```java
Executor executor1 = Executors.newFixedThreadPool(2);
```
线程数未达到核心数,则创建新的核心线程,否则加入无界队列 LinkedBlockingQueue。等待核心线程执行完任务去队列取任务。
### 2、CachedThreadPool
没有核心线程,非核心线程无限的。有一个阻塞队列 SynchronousQueue。
```java
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
```
```java
Executor executor2 = Executors.newCachedThreadPool();
```
这里使用的是不存储元素的阻塞队列,所以有元素进入,必须立马取走,由于非核心线程又是最大的,所以相当于有任务进来就会别无限创建新的线程去执行,然后 60S 后自动销毁。
比较适合有大量任务需要立即处理并且耗时较少的任务。
### 3、SingleThreadExecutor
只有一个线程
```java
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
```
```java
Executor executor3 = Executors.newSingleThreadExecutor();
```
没任务,就创建核心线程去执行
有任务,放入无界队列,
SingleThreadExecutor 能够确保所有的任务在一个线程中按照顺序去执行。
### 4、ScheduledThreadPool
创建一个定长的线程池,而且支持定时的以及周期性的任务执行。
```java
Executor executor4 = Executors.newScheduledThreadPool(1);
```
- Java 面试题
- String、StringBuffer、StringBuilder 的区别?
- Java 中的四种引用
- 接口和抽象类的本质区别
- 集合框架
- 集合概述
- ArrayList 源码分析
- LinkedList 源码分析
- HashMap 源码分析
- LinkedHashMap 源码分析
- Android提供的 LruCache 的分析
- LinkedList 和 ArrayList 的区别
- 多线程
- 实现多线程的几种方式
- 线程的几种状态
- Thread 的 start() 和 run() 的区别
- sleep() 、yield() 和 wait() 的区别 ?
- notify() 和 notifyAll() 的区别?
- 保证线程安全的方式有哪几种?
- Synchronized 关键字
- volatile 和 synchronized 的区别?
- 如何正确的终止一个线程?
- ThreadLocal 原理分析
- 线程池
- 多线程的三个特征
- 五种线程池,四种拒绝策略,三种阻塞队列
- 给定三个线程如何顺序执行完以后在主线程拿到执行结果
- Java 内存模型
- 判定可回收对象算法
- equals 与 == 操作符
- 类加载机制
- 类加载简单例子
- 算法
- 时间、空间复杂度
- 冒泡排序
- 快速排序
- 链表反转
- IO
- 泛型
- Kolin 面试题
- Android 面试题
- Handler 线程间通信
- Message、MessageQueue、Looper、Handler 的对象关系
- Handler 使用
- Handler 源码分析
- HandlerThread
- AsyncTask
- IntentService
- 三方框架
- Rxjava
- rxjava 操作符有哪些
- 如何解决 RxJava 内存泄漏
- Rxjava 线程切换原理
- map和 flatmap 的区别
- Databinding引起的 java方法大于 65535 的问题
- Glide
- Glide 的缓存原理
- Glide 是如何和生命周期绑定的?不同的Context 有什么区别?
- Glide 、Picasso 、的区别,优劣势,如何选择?
- Jetpack
- 源码分析
- EventBus
- EventBus 源码分析
- RxBus 替代 EventBus
- OkHttp
- OkHttp 源码分析
- OkHttp 缓存分析
- RxPermission
- RxPermission 源码分析
- Retrofit
- create
- Retrofit 源码分析
- 优化
- 启动优化
- 布局优化
- 绘制优化
- 内存优化
- 屏幕适配
- 组件
- Activity
- Frgment
- Service
- ContentProvider
- BroadcastReceiver
- 进程间通信
- Binder机制和AIDL
- AILD 中的接口和普通的接口有什么区别
- in、out、inout 的区别
- Binder 为什么只需要拷贝一次
- 在android中,请简述jni的调用过程
- 生命周期
- Activity 生命周期
- Fragment 生命周期
- Service 生命周期
- onSaveInstanceState() 与 onRestoreIntanceState()
- 前沿技术
- 组件化
- 模块化
- 插件化
- 热更新
- UI - View
- Android 动画
- 事件分发机制
- WebView
- 系统相关
- 谈谈对 Context 的理解
- Android 版本
- App应用启动流程
- App 的打包
- App 的加固
- App 的安装
- Activity 启动流程
- ClassLoader
- Lru 算法加载 Bitmap 三级缓存原理
- Parcelable 和 Serializable 的区别
- Activity的启动流程
- 相关概念
- 网络相关
- Http
- Https
- Http 和 Https 的区别
- 为什么要进行三次握手和四次挥手?
- OkHttp使用Https访问服务器时信任所有证书
- 设计模式
- 单例模式
- 构建者模式
- 工厂模式
- 外观模式
- 代理模式