相当于一个容器,容纳的是Thread或者Runable
1、每一个线程都是需要CUP去分配的,如果总是需要new thread,那么会大量耗费CPU资源,导致应用运行变慢,甚至oom
2、ThreadPoolExecutor可以减少销毁和创建的次数,每个工作线程可以重复利用,可执行多个任务
3、可以根据手机cpu核数来控制最大线程数,保证程序合理运行
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
TimeUnit unit, BlockingQueue workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
TimeUnit unit, BlockingQueue workQueue,
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
TimeUnit unit, BlockingQueue workQueue,
RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
}
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
TimeUnit unit,BlockingQueue workQueue,
ThreadFactory threadFactory, RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
参数
public ThreadPoolExecutor(
int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue,
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
corePoolSize: 核心线程池大小,也就是是线程池中的最小线程数;核心线程在allowCoreThreadTimeout被设置为true时会超时退出,默认情况下不会退出;
maximumPoolSize:最大线程池大小,当活动线程数达到这个值,后续任务会被阻塞
keepAliveTime:
1、线程池中超过corePoolSize数目的非核心线程最大存活时间;闲置时的超时时长,超过这个值后,闲置线程就会被回收,直到线程数量等于corePoolSize。如果allowCoreThreadTimeout设置为true,则所有线程均会退出直到线程数量为0。
2、如果池中当前有多于 corePoolSize 的线程,则这些多出的线程在空闲时间超过 keepAliveTime 时将会终止,这提供了当池处于非活动状态时减少资源消耗的方法。如果池后来变得更为活动,则可以创建新的线程。
unit: 线程池维护线程所允许的空闲时间的单位
workQueue:
1、线程池所使用的缓冲队列
2、执行前用于保持任务的队列,也就是线程池的缓存队列。此队列仅保持由 execute 方法提交的 Runnable 任务
threadFactory:线程工厂,为线程池提供创建新线程的功能,它是一个接口,只有一个方法:Thread newThread(Runnable r)
RejectedExecutionHandler:
1、当提交任务数超过maxmumPoolSize+workQueue之和时,任务会交给RejectedExecutionHandler来处理
2、线程池对拒绝任务的处理策略。一般是队列已满或者无法成功执行任务,这时ThreadPoolExecutor会调用handler的rejectedExecution方法来通知调用者
线程池几个参数的理解:
1. 比如去火车站买票, 有10个售票窗口, 但只有5个窗口对外开放. 那么对外开放的5个窗口称为核心线程数corePoolSize,而最大线程数maximumPoolSize是10个窗口.
2. 如果5个窗口都被占用, 那么后来的人就必须在后面排队, 但后来售票厅人越来越多, 已经人满为患, 就类似于线程队列new LinkedBlockingQueue<Runnable>()已满.
3. 这时候火车站站长下令, 把剩下的5个窗口也打开, 也就是目前已经有10个窗口同时运行. 后来又来了一批人
4. 10个窗口也处理不过来了, 而且售票厅人已经满了, 这时候站长就下令封锁入口,不允许其他人再进来, 这就是线程异常处理策略.
5. 而线程存活时间keepAliveTime指的是, 允许售票员休息的最长时间, 以此限制售票员偷懒的行时间。休息一下在处理。
一个任务通过 execute(Runnable)方法被添加到线程池,任务就是一个 Runnable类型的对象,任务的执行方法就是Runnable类型对象的run()方法。
当线程池小于corePoolSize时,新提交任务将创建一个新线程执行任务,即使此时线程池中存在空闲线程
当线程池达到corePoolSize时,新提交任务将被放入workQueue中,等待线程池中任务调度执行
当提交任务数超过【maximumPoolSize+阻塞队列大小】时,新提交任务由RejectedExecutionHandler处理 (关于这里,网上90%以上的人说当任务数>=maximumPoolSize时就会被拒绝,我不知道依据在哪里,也不知道代码验证过没,经过我的验证这种说法是不成立的,具体的看下边日志分析)
当线程池中超过corePoolSize线程,空闲时间达到keepAliveTime时,关闭空闲线程
当设置allowCoreThreadTimeOut(true)时,线程池中corePoolSize线程空闲时间达到keepAliveTime也将关闭
模拟音乐播放器,点击下载音乐
package com.bourne.android_common.ThreadDemo;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import com.bourne.android_common.R;
import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ThreadPoolExecutorActivity extends AppCompatActivity {
private final int CORE_POOL_SIZE = 4;//核心线程数
private final int MAX_POOL_SIZE = 5;//最大线程数
private final long KEEP_ALIVE_TIME = 10;//空闲线程超时时间
private ThreadPoolExecutor executorPool;
private int songIndex = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_thread_pool_executor);
// 创建线程池
// 创建一个核心线程数为4、最大线程数为5的线程池
executorPool = new ThreadPoolExecutor(CORE_POOL_SIZE, MAX_POOL_SIZE, KEEP_ALIVE_TIME,
TimeUnit.SECONDS, new LinkedBlockingQueue(),
Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
}
/**
* 点击下载
*
* @param view
*/
public void begin(View view) {
songIndex++;
try {
executorPool.execute(new WorkerThread("歌曲" + songIndex));
} catch (Exception e) {
Log.e("threadtest", "AbortPolicy...已超出规定的线程数量,不能再增加了....");
}
// 所有任务已经执行完毕,我们在监听一下相关数据
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(20 * 1000);
} catch (Exception e) {
}
Li("monitor after");
}
}).start();
}
private void Li(String mess) {
Log.i("threadtest", "monitor " + mess
+ " CorePoolSize:" + executorPool.getCorePoolSize()
+ " PoolSize:" + executorPool.getPoolSize()
+ " MaximumPoolSize:" + executorPool.getMaximumPoolSize()
+ " ActiveCount:" + executorPool.getActiveCount()
+ " TaskCount:" + executorPool.getTaskCount()
);
}
public class WorkerThread implements Runnable {
private String threadName;
public WorkerThread(String threadName) {
this.threadName = threadName;
}
@Override
public synchronized void run() {
boolean flag = true;
try {
while (flag) {
String tn = Thread.currentThread().getName();
//模拟耗时操作
Random random = new Random();
long time = (random.nextInt(5) + 1) * 1000;
Thread.sleep(time);
Log.e("threadtest", "线程\"" + tn + "\"耗时了(" + time / 1000 + "秒)下载了第<" + threadName + ">");
//下载完了跳出循环
flag = false;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public String getThreadName() {
return threadName;
}
}
}
xml布局
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAllCaps="false"
android:layout_weight="1"
android:onClick="begin"
android:text="点击下载一首歌曲"/>
LinearLayout>
效果图:
界面操作:
1、这里设置了4个核心线程,也就是4个下载线程
private final int CORE_POOL_SIZE = 4;//核心线程数
/**
* 点击下载
*
* @param view
*/
public void begin(View view) {
songIndex++;
try {
executorPool.execute(new WorkerThread("歌曲" + songIndex));
} catch (Exception e) {
Log.e("threadtest", "AbortPolicy...已超出规定的线程数量,不能再增加了....");
}
}
2、耗时操作,下载完毕跳出循环
public class WorkerThread implements Runnable {
private String threadName;
public WorkerThread(String threadName) {
this.threadName = threadName;
}
@Override
public synchronized void run() {
boolean flag = true;
try {
while (flag) {
String tn = Thread.currentThread().getName();
//模拟耗时操作
Random random = new Random();
long time = (random.nextInt(5) + 1) * 1000;
Thread.sleep(time);
Log.e("threadtest", "线程\"" + tn + "\"耗时了(" + time / 1000 + "秒)下载了第<" + threadName + ">");
//下载完了跳出循环
flag = false;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public String getThreadName() {
return threadName;
}
}
ThreadPoolExecutor文档中文版链接
ThreadPoolExecutor文档英文版链接
ThreadPoolExecutor使用和思考(上)-线程池大小设置与BlockingQueue的三种实现区别
android线程池ThreadPoolExecutor的理解
Android中的线程池 ThreadPoolExecutor