当我们需要频繁地创建多个线程进行耗时操作时,每次都通过new Thread实现并不是一种好 的方式,每次new Thread新建和销毁对象性能较差,线程缺乏统一管理,可能无限制新建线程, 相互之间竞争,可能占用过多系统资源导致死锁,并且缺乏定时执行、定期执行、线程中断等功能。 好在Java提供了 4种线程池,它能够有效地管理、调度线程,避免过多的资源消耗,它强大到几 乎不需要幵发人员自定义的程度。它的优点如下:
(1) 重用存在的线程,减少对象创建、销毁的幵销;
(2) 可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞;
(3) 提供定时执行、定期执行、单线程、并发数控制等功能。
线程池原理简单地解释就是会创建多个线程并且进行管理,提交给线程的任务会被线程池指派给 其中的线程进行执行,通过线程池的统一调度、管理使得多线程的使用更简单、高效。如下图所示。
它的功能是启动指定数量的线程以及将任务添加到一个队列中,并且将任务分发给空闲的线程。ExecutorService 的生命周期包括三种状态:运行、关闭、终止。创建后便进入运行状态,当调用的 shutdown() 方法时,便进入关闭状态,此时意味着 ExecutorService 不再接受新的任务,但它还在执行已提交的任务。当所有已提交的任务执行完后,就变成终止状态。
ThreadPoolExecutor 的构造函数如下:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue,
RejectedExecutionHandler handler)
下面对这几个参数详细说明:
ThreadPoolExecutor 的使用流程:
/**
* 1.创建基本线程池
* corePoolSize:该线程池中核心线程的数量。
* maximumPoolSize:最大线程数量
* keepAliveTime:非核心线程空闲时要等待下一个任务到来的时间
* unit:上面时间属性的单位
* workQueue:任务队列
*/
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
3,
5,
1,
TimeUnit.SECONDS,
new LinkedBlockingQueue(100));
/**
* 2. 向线程池提交任务:execute()
*/
threadPool.execute(new Runnable() {
@Override
public void run() {
// 线程执行任务
}
});
/**
* 3. 关闭线程池shutdown()
* 也可调用shutdownNow()关闭线程:threadPool.shutdownNow()
* shutdown:设置 线程池的状态 为 SHUTDOWN,然后中断所有没有正在执行任务的线程
* shutdownNow:设置 线程池的状态 为 STOP,然后尝试停止所有的正在执行或暂停任务的线程,并返回等待执行任务的列表
* 使用建议:一般调用shutdown()关闭线程池;若任务不一定要执行完,则调用shutdownNow()
*/
threadPool.shutdown();
上面介绍的是基本的线程池 ThreadPoolExecutor 简单介绍,但这个并不是常用的;后面会介绍几种常用的线程池,它们都是根据 ThreadPoolExecutor 的基础上延伸的。
启动指定数量的线程池 - FixedThreadPool
定时执行一些任务的线程池 - ScheduledThreadPool
可缓存的线程池 - CachedThreadPool
单个核线的线程池 - SingleThreadExecutor
这里面最常用的线程池是 FixedThreadPool ,下面来分别看一下它们的基本使用
启动指定数量的线程池 - FixedThreadPool
特点:该线程池只有核心线程,不会被回收;一般用于控制线程的最大并发数
//创建线程池
public ExecutorService mExecutor = Executors.newFixedThreadPool(5);
//创建线程对象
public class MyRunnable implements Runnable {
private final int width;
private final int height;
public MyRunnable(int imageWidth, int imageHeight) {
this.width = imageWidth;
this.height = imageHeight;
}
@Override
public void run() {
//逻辑处理
if (Looper.getMainLooper().getThread() == Thread.currentThread()) {
Log.e("wqs", "主线程: " + Thread.currentThread().getName());
} else {
Log.e("wqs", "不是主线程: " + Thread.currentThread().getName());
}
}
}
//向线程池添加任务
private synchronized void startRunnable() {
mExecutor.execute(new MyRunnable(100, 100));
}
//关闭线程池
private void stopExecutor(){
mExecutor.shutdown();
}
当我们一直调用上面的 startRunnable() 方法时,可以看出最多有五个线程来处理我们的任务,如下图:
定时执行一些任务的线程池 - ScheduledThreadPool
特点:核心线程数量一定,非核心线程数量多个,闲置时会立马回收非核心线程数量;一般用于定时的任务
//创建线程池
public ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);
//创建线程对象
public class MyRunnable implements Runnable {
private final int width;
private final int height;
public MyRunnable(int imageWidth, int imageHeight) {
this.width = imageWidth;
this.height = imageHeight;
}
@Override
public void run() {
//逻辑处理
if (Looper.getMainLooper().getThread() == Thread.currentThread()) {
Log.e("wqs", "主线程: " + Thread.currentThread().getName());
} else {
Log.e("wqs", "不是主线程: " + Thread.currentThread().getName());
}
}
}
//延迟开始执行
private synchronized void startRunnable() {
//延迟1s后执行任务
scheduledExecutorService.schedule(new MyRunnable(100, 100), 1, TimeUnit.SECONDS);
}
//延迟开始执行循环任务
private synchronized void startRunnableCycle() {
//延迟100ms后、每隔1000ms执行任务
scheduledExecutorService.scheduleAtFixedRate(new MyRunnable(100, 100),100,1000,TimeUnit.MILLISECONDS);
}
//关闭线程池
private void stopExecutor(){
scheduledExecutorService.shutdown();
}
可缓存的线程池 - CachedThreadPool
特点:只有非核心线程,线程数量不固定;一般用于执行大量耗时少的任务
//创建线程池
public ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
//创建线程对象
public class MyRunnable implements Runnable {
private final int width;
private final int height;
public MyRunnable(int imageWidth, int imageHeight) {
this.width = imageWidth;
this.height = imageHeight;
}
@Override
public void run() {
//逻辑处理
if (Looper.getMainLooper().getThread() == Thread.currentThread()) {
Log.e("wqs", "主线程: " + Thread.currentThread().getName());
} else {
Log.e("wqs", "不是主线程: " + Thread.currentThread().getName());
}
}
}
//开始执行
private synchronized void startRunnable() {
cachedThreadPool.execute(new MyRunnable(100, 100));
}
//关闭线程池
private void stopExecutor(){
cachedThreadPool.shutdown();
}
单个核线的线程池 - SingleThreadExecutor
特点:只有一个核心线程(是一个单线程);一般用于数据库操作
//创建线程池
public ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
//创建线程对象
public class MyRunnable implements Runnable {
private final int width;
private final int height;
public MyRunnable(int imageWidth, int imageHeight) {
this.width = imageWidth;
this.height = imageHeight;
}
@Override
public void run() {
//逻辑处理
if (Looper.getMainLooper().getThread() == Thread.currentThread()) {
Log.e("wqs", "主线程: " + Thread.currentThread().getName());
} else {
Log.e("wqs", "不是主线程: " + Thread.currentThread().getName());
}
}
}
//开始执行
private synchronized void startRunnable() {
singleThreadExecutor.execute(new MyRunnable(100, 100));
}
//关闭线程池
private void stopExecutor(){
singleThreadExecutor.shutdown();
}
上面是对线程池的简单理解。