在编程中经常会使用线程来异步处理任务,但是每个线程的创建和销毁都需要一定的开销。如果每次执行一个任务都需要开一个新线程去执行,则这些线程的创建和销毁将消耗大量的资源,并且线程都是“各自为政”的,很难对其进行控制,更何况有一堆的线程在执行。这时就需要线程池来对线程进行管理,通过线程池中线程的复用,减少创建和销毁线程的性能开销,也能控制线程池中的并发数,否则会因为大量的线程争夺CPU资源造成阻塞。
在Executors类中提供了创建FixedThreadPool的方法:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue());
}
FixedThreadPool的corePoolSize和maximunPoolSize都设置为创建FixedThreadPool指定的参数nThreads,也就是FixedThreadPool只有核心线程,并且数量是固定的,没有非核心线程。keepAliveTime设置为0L,意味着多余的线程会被立即终止。因为不会产生多余的线程,所以keepAliveTime是无效的参数。任务队列采用了无界的阻塞队列LinkedBlockingQueue。当线程数超过corePoolSize时,就将任务存储在任务队列中,当线程池有空闲线程时,则从任务队列中去取任务执行。
简单使用示例:
//1. 创建定长线程池对象 & 设置线程池线程数量固定为3
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
//2. 创建好Runnable类线程对象 & 需执行的任务
Runnable task = new Runnable() {
@Override
public void run() {
System.out.println("执行任务啦");
}
};
//3. 向线程池提交任务
fixedThreadPool.execute(task);
//4. 关闭线程池
fixedThreadPool.shutdown();
创建CachedThreadPool的代码如下所示:
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS,new SynchronousQueue());
}
CachedThreadPool的corePoolSize为0,maximunPoolSize设置为Integer.MAX_VALUE,这就意味着CacheThreadPool没有核心线程,非核心线程是无界的。keepAliveTime设置为60L,则空闲线程等待新任务的最长时间为60s。在此用了阻塞队列SynchronousQueue,它是一个不存储元素的阻塞队列,每个插入操作必须等待另一个线程的移除操作,同样任何一个移除操作都等待另一个线程的插入操作。
简单使用示例:
// 1. 创建可缓存线程池对象
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
// 2. 创建好Runnable类线程对象 & 需执行的任务
Runnable task = new Runnable() {
public void run() {
System.out.println("执行任务啦");
}
};
// 3. 向线程池提交任务
cachedThreadPool.execute(task);
// 4. 关闭线程池
cachedThreadPool.shutdown();
//当执行第二个任务时第一个任务已经完成
//那么会复用执行第一个任务的线程,而不用每次新建线程。
创建SingleThreadExecutor的代码如下所示:
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue()));
}
corePoolSize和maximumPoolSize都为1,意味着SingleThreadExecutor只有一个核心线程,其他参数都和FixedThreadPool一样。
简单使用示例:
// 1. 创建单线程化线程池
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
// 2. 创建好Runnable类线程对象 & 需执行的任务
Runnable task = new Runnable() {
public void run() {
System.out.println("执行任务啦");
}
};
// 3. 向线程池提交任务
singleThreadExecutor.execute(task);
// 4. 关闭线程池
singleThreadExecutor.shutdown();
创建ScheduledThreadPool的代码如下所示:
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
ScheduledThreadPool继承自ThreadPoolExecutor,它主要用于给定延时之后的运行任务或者定期处理任务。ScheduledThreadPoolExectour的构造方法如下:
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE,
DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
new DelayedWorkQueue());
}
从代码可以看出,ScheduledThreadPoolExecutor的构造方法最终调用的是ThreadPoolExecutor的构造方法。corePoolSize是传进来的固定数值,maximumPoolSize的值是Integer.MAX_VALUE。因为采用的是DelayedWorkQueue是无界的,所以maximumPoolSize这个参数是无效的。
简单使用示例:
// 1. 创建 定时线程池对象 & 设置线程池线程数量固定为5
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
// 2. 创建好Runnable类线程对象 & 需执行的任务
Runnable task =new Runnable(){
public void run(){
System.out.println("执行任务啦");
}
};
// 3. 向线程池提交任务
scheduledThreadPool.schedule(task, 1, TimeUnit.SECONDS); // 延迟1s后执行任务
scheduledThreadPool.scheduleAtFixedRate(task,10,1000,TimeUnit.MILLISECONDS);// 延迟10ms后、每隔1000ms执行任务
// 4. 关闭线程池
scheduledThreadPool.shutdown();
学了以上四种类型的线程池,准备在Android studio 工具进行编码测试时,竟然出现红线报错提示:线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。(前提是已安装阿里编码规约插件)。
也就是说,以上四种创建线程池的方式,是不符合编程规范的。
原因在于:
参数作用如下所示:
(1)AbortPolicy:默认策略,在需要拒绝任务时抛出RejectedExecutionException。
(2))CallerRunsPolicy:用调用者所在的线程来处理任务。此策略提供简单的反馈控制机制,能够减缓新任务的提交速度。
(3)DiscardPolicy:不能执行的任务,并将该任务删除。
(4)DiscardOldestPolicy:丢弃队列最近的任务,并执行当前的任务。
ThreadPoolExecutor创建线程池示例:
public class ThreadPoolProxy {
private volatile ThreadPoolExecutor mExecutor;
/**
* 核心线程数
*/
private int mCorePoolSize;
/**
* 最大线程数
*/
private int mMaximumPoolSize;
/**
* 保持时间
*/
private long mKeepAliveTime;
public ThreadPoolProxy(int corePoolSize, int maximumPoolSize, long keepAliveTime) {
super();
mCorePoolSize = corePoolSize;
mMaximumPoolSize = maximumPoolSize;
mKeepAliveTime = keepAliveTime;
}
/**
* 创建唯一的线程池
*/
private ThreadPoolExecutor initThreadPoolExecutor() {
if (null == mExecutor) {
synchronized (ThreadPoolProxy.class) {
if (null == mExecutor) {
TimeUnit unit = TimeUnit.MILLISECONDS;
//(无界队列)可变的阻塞队列
BlockingQueue workQueue = new LinkedBlockingDeque<>();
//默认线程工厂
ThreadFactory threadFactory = Executors.defaultThreadFactory();
//异常捕获器,弃任务并抛出RejectedExecutionException异常。
RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();
mExecutor = new ThreadPoolExecutor(
mCorePoolSize,
mMaximumPoolSize,
mKeepAliveTime,
unit,
workQueue,
threadFactory,
handler);
}
}
}
return mExecutor;
}
/**
* 执行任务
*
* @param task
*/
public void execute(Runnable task) {
initThreadPoolExecutor();
mExecutor.execute(task);
}
/**
* 移除未执行任务,已经执行的不会被移除
*
* @param task
*/
public void remove(Runnable task) {
initThreadPoolExecutor();
mExecutor.remove(task);
}
}