1. 内部原理逻辑
当线程池运行时,遵循以下工作逻辑:
二、几种常见的线程池
1、ThreadPoolExecutor 创建基本线程池
创建线程池,主要是利用ThreadPoolExecutor这个类,而这个类有几种构造方法,其中参数最多的一种构造方法如下:
/\*
\*@ ThreadPoolExecutor构造参数介绍
\*/
public ThreadPoolExecutor(
//核心线程数,除非allowCoreThreadTimeOut被设置为true,否则它闲着也不会死
int corePoolSize,
//最大线程数,活动线程数量超过它,后续任务就会排队
int maximumPoolSize,
//超时时长,作用于非核心线程(allowCoreThreadTimeOut被设置为true时也会同时作用于核心线程),闲置超时便被回收
long keepAliveTime,
//枚举类型,设置keepAliveTime的单位,有TimeUnit.MILLISECONDS(ms)、TimeUnit. SECONDS(s)等
TimeUnit unit,
//缓冲任务队列,线程池的execute方法会将Runnable对象存储起来
BlockingQueue<Runnable> workQueue,
//线程工厂接口,只有一个new Thread(Runnable r)方法,可为线程池创建新线程
ThreadFactory threadFactory)
- corePoolSize: 该线程池中核心线程的数量。
- maximumPoolSize:该线程池中最大线程数量。(区别于corePoolSize)
- keepAliveTime:从字面上就可以理解,是非核心线程空闲时要等待下一个任务到来的时间,当任务很多,每个任务执行时间很短的情况下调大该值有助于提高线程利用率。注意:当allowCoreThreadTimeOut属性设为true时,该属性也可用于核心线程。
- unit:上面时间属性的单位
- workQueue:任务队列,后面详述。
- threadFactory:线程工厂,可用于设置线程名字等等,一般无须设置该参数。
ThreadPoolExecutor的各个参数所代表的特性注释中已经写的很清楚了,那么ThreadPoolExecutor执行任务时的心路历程是什么样的呢?(以下用currentSize表示线程池中当前线程数量)
- 当currentSize<corePoolSize时,没什么好说的,直接启动一个核心线程并执行任务。
- 当currentSize>=corePoolSize、并且workQueue未满时,添加进来的任务会被安排到workQueue中等待执行。
- 当workQueue已满,但是currentSize<maximumPoolSize时,会立即开启一个非核心线程来执行任务。
- 当currentSize>=corePoolSize、workQueue已满、并且currentSize>maximumPoolSize时,调用handler默认抛出RejectExecutionExpection异常。
设置好几个参数就可以创建一个基本的线程池,而之后的各种线程池都是在这种基本线程池的基础上延伸的。
下面贴个自己写的demo来熟悉具体的使用并且加深影响:
//创建基本线程池
final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(3,5,1,TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(100));
设置一个按钮mThreadPoolExecute,并在点击事件中使用线程池
/\*\*
\* 基本线程池使用
\*/
mThreadPoolExecute.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
for(int i = 0;i<30;i++){
final int finali = i;
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
Log.d("Thread", "run: "+finali);
Log.d("当前线程:",Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
threadPoolExecutor.execute(runnable);
}
}
});
结果会每2s打印三个日志。
具体过程:
- execute一个线程之后,如果线程池中的线程数未达到核心线程数,则会立马启用一个核心线程去执行。
- execute一个线程之后,如果线程池中的线程数已经达到核心线程数,且workQueue未满,则将新线程放入workQueue中等待执行。
- execute一个线程之后,如果线程池中的线程数已经达到核心线程数但未超过非核心线程数,且workQueue已满,则开启一个非核心线程来执行任务。
- execute一个线程之后,如果线程池中的线程数已经超过非核心线程数,则拒绝执行该任务,采取饱和策略,并抛出RejectedExecutionException异常。