前言
Executors(java.util.concurrent.Executors)框架,是Java中用于创建线程池的工厂类。CachedThreadPool FixedThreadPool ScheduledThreadPool SingleThreadExecutor等。
- newCachedThreadPool():根据需要创建新线程的线程池
- newFixedThreadPool(int n):固定线程数的线程池,超过的任务会在队列中等待
- newScheduledThreadPool(int corePoolSize):延迟执行任务,或周期性执行
- newSingleThreadExecutor():使用单个worker线程的线程池,无界队列运行该线程
线程池生命周期:创建、运行、关闭三个阶段。
ThreadPoolExecutor
实现自定义线程池。
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
- corePoolSize:核心线程数,线程池维护的最小线程数。
- maximumPoolSize:最大线程数,允许的最大线程数。
- keepAliveTimes:当前线程池线程数量超过核心线程数时,多余空闲线程在终止前等待新任务的最长时间。
- unit:keepAliveTimes时间单位
- workQueue:等待执行任务的阻塞队列
- threadFactory:线程工厂
- defaultHandler:拒绝策略,达到最大线程数后的拒绝策略。
自定义线程池:子线程切换、主线程切换、延迟任务、周期任务
package com.georege.tools;
import android.os.Handler;
import android.os.Looper;
import androidx.annotation.NonNull;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 异步任务执行工具类
*
*/
public class TaskExecutor {
/**
* 当前设备的CPU数
*/
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
/**
* 当前线程池默认的线程数
*/
private static final int CORE_POOL_SIZE = CPU_COUNT + 3;
/**
* 线程池最大线程数
*/
private static final int MAX_POOL_SIZE = CPU_COUNT * 2 + 1;
/**
* 调度任务最大线程池数
*/
private static final int MAX_SCHEDULED_POOL_SIZE = 2;
/**
* 是否keep alive
*/
private static final int KEEP_ALIVE = 1;
/**
* 线程池
*/
private static ExecutorService sExecutorService = null;
/**
* 延时定时线程池
*/
private static ScheduledThreadPoolExecutor sScheduledThreadPoolExecutor = null;
/**
* 主线程handler
*/
private static Handler sMainHandler = null;
/**
* 线程池构造
*/
private synchronized static void ensureThreadPoolExecutor() {
if (sExecutorService == null) {
// 线程池构造7个参数:核心线程数;最大线程数;线程空闲时间;时间单位;存放任务队列;创建线程工厂;
// 当任务满了后再次提交任务时的策略(丢弃阻塞队列中靠前的任务,并执行当前任务)
sExecutorService = new ThreadPoolExecutor(CORE_POOL_SIZE, MAX_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS,
new LinkedBlockingDeque<Runnable>(), new DefaultThreadPoolFactory(), new ThreadPoolExecutor.DiscardOldestPolicy());
}
}
/**
* 延时定时线程池,任务延期执行或定期执行
*/
private synchronized static void ensureScheduledThreadPoolExector() {
if (sScheduledThreadPoolExecutor == null) {
// 继承ThreadPoolExecutor。
// 核心线程数;拒绝策略(直接抛出异常,阻止系统正常运行)
sScheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(MAX_SCHEDULED_POOL_SIZE, new ThreadPoolExecutor.AbortPolicy());
}
}
/**
* 初始化主线程handler
*/
private synchronized static void ensureMainHandler() {
if (sMainHandler == null) {
sMainHandler = new Handler(Looper.getMainLooper());
}
}
/**
* 执行异步任务,默认线程池
*
* @param task 需要异步执行的任务
*/
public static Future<?> executeTask(Runnable task) {
ensureThreadPoolExecutor();
return sExecutorService.submit(task);
}
/**
* 执行异步任务,并获取结果,默认线程池
*
* @param task 需要异步执行的任务
* @return 任务执行结果,需要自行处理异常
*/
public static <T> Future<?> executeTaskWithResult(Callable<T> task) {
ensureThreadPoolExecutor();
return sExecutorService.submit(task);
}
/**
* 延时执行一个异步任务
*
* @param delay 延时时间,毫秒
* @param task 需要执行的异步任务
* @return 延时执行结果,不需要可不理会
*/
public static ScheduledFuture<?> scheduledTask(long delay, Runnable task) {
ensureScheduledThreadPoolExector();
return sScheduledThreadPoolExecutor.schedule(task, delay, TimeUnit.MILLISECONDS);
}
/**
* 周期执行异步任务
*
* @param task 需要周期执行的异步任务
* @param initDelay 初始延时, 毫秒
* @param period 周期,毫秒
*/
public static ScheduledFuture<?> scheduleAtFixedRate(Runnable task, long initDelay, long period) {
ensureScheduledThreadPoolExector();
return sScheduledThreadPoolExecutor.scheduleAtFixedRate(task, initDelay, period, TimeUnit.MILLISECONDS);
}
/**
* 在UI线程中执行任务
*
* @param task 需要执行的任务
*/
public static void runTaskOnUiThread(Runnable task) {
if (Looper.myLooper() == Looper.getMainLooper()) {
task.run();
} else {
ensureMainHandler();
sMainHandler.post(task);
}
}
/**
* 在UI线程中延时执行任务
*
* @param delay 延时时间,毫秒
* @param task 需要执行的任务
*/
public static void scheduledTaskOnUiThread(long delay, Runnable task) {
ensureMainHandler();
sMainHandler.postDelayed(task, delay);
}
/**
* 移除UI线程延时任务
*
* @param task
*/
public static void removeTaskOnUiThread(Runnable task) {
ensureMainHandler();
sMainHandler.removeCallbacks(task);
}
/**
* 清理并回收线程池占用的资源(非必要时无需调用)
*/
public static void shutdown() {
if (sExecutorService != null) {
sExecutorService.shutdown();
sExecutorService = null;
}
}
/**
* 默认的线程池工厂,线程使用默认优先级
*/
private static class DefaultThreadPoolFactory implements ThreadFactory {
/**
* 当前线程池号
*/
private static final AtomicInteger THREAD_POOL_NUM = new AtomicInteger(1);
/**
* 线程所属分组
*/
private final ThreadGroup group;
/**
* 线程代号
*/
private final AtomicInteger threadNum = new AtomicInteger(1);
/**
* 当前总线程数
*/
private final AtomicInteger totalThreadNum = new AtomicInteger(1);
/**
* 线程名前缀
*/
private final String namePrefix;
/**
* 默认线程工厂
*/
DefaultThreadPoolFactory() {
SecurityManager s = System.getSecurityManager();
group = s != null ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
namePrefix = "pool-id-" + THREAD_POOL_NUM.getAndIncrement();
}
@Override
public Thread newThread(@NonNull Runnable r) {
Thread thread = new Thread(group, r,
namePrefix + " thread-id-" + threadNum.getAndIncrement() + " total-thread-num-" + totalThreadNum.getAndIncrement());
thread.setPriority(Thread.NORM_PRIORITY);
if (thread.isDaemon()) {
thread.setDaemon(false);
}
return thread;
}
}
}
总结
- ScheduledThreadPoolExecutor最大线程数是Integer.MAX_VALUE
- ScheduledThreadPoolExecutor工作队列是DelayedWorkQueue按执行时间作为比较优先队列,使用二叉堆数据结构,每次take任务都拿根节点的任务(距离执行时间最近的)。 3.ScheduledThreadPoolExecutor中,period=0 抛出异常;scheduleAtFixedRate period>0 按照第一个任务起点,时间顺序执行,不考虑任务花费的时间;scheduleWithFixedDelay period<0 按照上次任务执行完成的时间延迟period时间执行