一、线程池的使用缘由及好处:
在android开发中使用多线程异步来处理相关任务,用newThread来创建一个子线程进行处理,会出现许多问题:
1:在任务众多的情况下,系统要为每一个任务创建一个线程,任务执行完毕后销毁每一个线程,会造成线程频繁地创建与销毁。
2:多个线程频繁地创建会占用大量的资源,并且在资源竞争的时候就容易出现问题,同时这么多的线程缺乏一个统一的管理,容易造成界面的卡顿。
3:多个线程频繁地销毁,会频繁地调用GC机制,这会使性能降低,又非常耗时。
总而言之:频繁地为每一个任务创建一个线程,缺乏统一管理,降低性能,并且容易出现问题。
为了解决这些问题,就要用到今天的主角——线程池.
使用线程池使用的好处:
1:对多个线程进行统一地管理,避免资源竞争中出现的问题。
2:对线程进行复用,线程在执行完任务后不会立刻销毁,而会等待另外的任务,这样就不会频繁地创建、销毁线程和调用GC。
3:JAVA提供了一套完整的ExecutorService线程池创建的api,可创建多种功能不一的线程池,使用起来比较方便。
二、几种常用的线程池:
Android中的线程池来源于java,主要是通过Executor 来派生特定类型的线程池,不同类型的线程池有不同的意义。Executor是一个接口,真正地实现为ThreadPoolExecutor,他提供了一系列的参数来配置线程池。不同参数意味着不同的线程池。
线程池分为四种以及一种基本线程池:
ThreadPoolExecutor (基本线程池)
创建一个基本的线程池,之后的各种线程池都是在这种基本线程池的基础上延伸的
创建线程池,主要是利用ThreadPoolExecutor这个类,而这个类有几种构造方法,其中参数最多的一种构造方法如下:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
...
}
corePoolSize: 该线程池中核心线程的数量。
maximumPoolSize:该线程池中最大线程数量。(区别于corePoolSize)
keepAliveTime:非核心线程空闲时要等待下一个任务到来的时间,当任务很多,每个任务执行时间很短的情况下调大该值有助于提高线程利用率。注意:当allowCoreThreadTimeOut属性设为true时,该属性也可用于核心线程。
unit:时间属性的单位
workQueue:任务队列
threadFactory:线程工厂,可用于设置线程名字等等,一般无须设置该参数。
四种线程池:
FixedThreadPool (可重用固定线程数)
①可控制线程最大并发数(线程数固定)
②超出的线程会在队列中等待
③只有核心线程,无非核心线程,并且阻塞队列无界
使用优势:能够更快的响应外界的请求参数。
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L,TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
CachedThreadPool (缓存线程池)
特点:
① 线程数无限制
② 没有核心线程,都是非核心线程
优势:比较适合用来执行大量的但是耗时较少的任务。
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
ScheduledThreadPool(定时延时线程池)
使用场景:用于执行定时任务和具有固定周期的重复任务。
SingleTreadExecutor(单个核心线程)
使用场景:按顺序执行,不需要处理同步的问题
封装工具类:
/**
* 线程池封装
*
* @author SJR
* created at 2019/1/5
*/
public class ThreadPoolManager {
private static ThreadPoolManager mInstance;
public static ThreadPoolManager getInstance() {
if (mInstance == null) {
synchronized (ThreadPoolManager.class) {
if (mInstance == null) {
mInstance = new ThreadPoolManager();
}
}
}
return mInstance;
}
/**
* 核心线程池的数量,同时能够执行的线程数量
*/
private int corePoolSize;
/**
* 最大线程池数量,表示当缓冲队列满的时候能继续容纳的等待任务的数量
*/
private int maximumPoolSize;
/**
* 存活时间
*/
private long keepAliveTime = 1;
private TimeUnit unit = TimeUnit.HOURS;
private ThreadPoolExecutor executor;
private ThreadPoolManager() {
/**
* 给corePoolSize赋值:当前设备可用处理器核心数*2 + 1,能够让cpu的效率得到最大程度执行(有研究论证的)
*/
corePoolSize = Runtime.getRuntime().availableProcessors() * 2 + 1;
//虽然maximumPoolSize用不到,但是需要赋值,否则报错
maximumPoolSize = corePoolSize;
executor = new ThreadPoolExecutor(
//当某个核心任务执行完毕,会依次从缓冲队列中取出等待任务
corePoolSize,
//5,先corePoolSize,然后new LinkedBlockingQueue<Runnable>(),然后maximumPoolSize,但是它的数量是包含了corePoolSize的
maximumPoolSize,
//表示的是maximumPoolSize当中等待任务的存活时间
keepAliveTime,
unit,
//缓冲队列,用于存放等待任务,Linked的先进先出
new LinkedBlockingQueue<Runnable>(),
//创建线程的工厂
// Executors.defaultThreadFactory(),
new DefaultThreadFactory(Thread.NORM_PRIORITY, "tiaoba-pool-"),
//用来对超出maximumPoolSize的任务的处理策略
new ThreadPoolExecutor.AbortPolicy()
);
}
/**
* 执行任务
*
* @param runnable
*/
public void execute(Runnable runnable) {
if (executor == null) {
//线程池执行者。
//参1:核心线程数;参2:最大线程数;参3:线程休眠时间;参4:时间单位;参5:线程队列;参6:生产线程的工厂;参7:线程异常处理策略
executor = new ThreadPoolExecutor(
corePoolSize,
maximumPoolSize,
keepAliveTime,
TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(),
// Executors.defaultThreadFactory(),
new DefaultThreadFactory(Thread.NORM_PRIORITY, "tiaoba-pool-"),
new ThreadPoolExecutor.AbortPolicy());
}
if (runnable != null) {
executor.execute(runnable);
}
}
/**
* 移除任务
*/
public void remove(Runnable runnable) {
if (runnable != null) {
executor.remove(runnable);
}
}
/**
* 创建线程的工厂,设置线程的优先级,group,以及命名
*/
private static class DefaultThreadFactory implements ThreadFactory {
/**
* 线程池的计数
*/
private static final AtomicInteger poolNumber = new AtomicInteger(1);
/**
* 线程的计数
*/
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final ThreadGroup group;
private final String namePrefix;
private final int threadPriority;
DefaultThreadFactory(int threadPriority, String threadNamePrefix) {
this.threadPriority = threadPriority;
this.group = Thread.currentThread().getThreadGroup();
namePrefix = threadNamePrefix + poolNumber.getAndIncrement() + "-thread-";
}
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);
if (t.isDaemon()) {
t.setDaemon(false);
}
t.setPriority(threadPriority);
return t;
}
}
}
使用方法:
Runnable testRunnable= new Runnable(){
@Override
public void run(){
//TODO 相关处理逻辑
...
···
}
}
ThreadPoolManager.getInstance().execute(testRunnable));