摘要
- 线程池 ThreadPoolExecutor 的API说明
- 核心API说明
- 自定义ThreadPoolExecutor
- Android中的使用
线程池API
核心API分析
相关参数分析
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private static final int COUNT_BITS = Integer.SIZE - 3;
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
// runState is stored in the high-order bits
private static final int RUNNING = -1 << COUNT_BITS;
private static final int SHUTDOWN = 0 << COUNT_BITS;
private static final int STOP = 1 << COUNT_BITS;
private static final int TIDYING = 2 << COUNT_BITS;
private static final int TERMINATED = 3 << COUNT_BITS;
// Packing and unpacking ctl
private static int runStateOf(int c) { return c & ~CAPACITY; }
private static int workerCountOf(int c) { return c & CAPACITY; }
private static int ctlOf(int rs, int wc) { return rs | wc; }
复制代码
- AtomicInteger ctl 维护两个参数 线程数量和运行状态 workcount的数量 (2^29)-1 (大约50亿)、
- runStateOf(ctl) 获取运行状态
- workerCountOf(ctl) 获取线程数 不区分核心线程和非核心线程的
- 线程池的几种状态
RUNNING: Accept new tasks and process queued tasks
SHUTDOWN: Don't accept new tasks, but process queued tasks
STOP: Don't accept new tasks, don't process queued tasks,
and interrupt in-progress tasks
TIDYING: All tasks have terminated, workerCount is zero,
the thread transitioning to state TIDYING
will run the terminated() hook method
TERMINATED: terminated() has completed
复制代码
核心方法分析
构造方法
/**
* Creates a new {@code ThreadPoolExecutor} with the given initial
* parameters.
*
* @param corePoolSize 核心线程数量,这些线程即使空闲也会存在,除非设置allowCoreThreadTimeOut
* @param maximumPoolSize 线程池中允许的最大线程数
* @param keepAliveTime 闲置线程被销毁的超时时间(针对非核心线程,除非核心线程设置了allowCoreThreadTimeOut).
* @param unit keepAliveTime的时间单位
* @param workQueue 缓存没有被执行的任务队列,该队列只缓存execute方法提交的任务
* @param threadFactory executor用来创建线程的工厂
* @param handler 当执行器由于线程数量和队列达到最大值要使用的处理策略、
* @throws IllegalArgumentException if one of the following holds:<br>
* {@code corePoolSize < 0}<br>
* {@code keepAliveTime < 0}<br>
* {@code maximumPoolSize <= 0}<br>
* {@code maximumPoolSize < corePoolSize}
* @throws NullPointerException if {@code workQueue}
* or {@code threadFactory} or {@code handler} is null
*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> 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;
}
复制代码
核心方法之execute()
/**
* Executes the given task sometime in the future. The task
* may execute in a new thread or in an existing pooled thread.
*
* If the task cannot be submitted for execution, either because this
* executor has been shutdown or because its capacity has been reached,
* the task is handled by the current {@code RejectedExecutionHandler}.
*
* @param command the task to execute
* @throws RejectedExecutionException at discretion of
* {@code RejectedExecutionHandler}, if the task
* cannot be accepted for execution
* @throws NullPointerException if {@code command} is null
*/
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
/*
* Proceed in 3 steps:
*
* 1.如果运行中的线程数量小于核心线程数量,尝试着开启一个新的线程,并运行这个任务
* 由于addWorker方法使用原子性的检查runState 和 workerCount,所以阻止了添加thread
* 的错误.
* 2.如果一个task能够被加入队列,我们仍然需要二次检查我们是否应该把这个线程添加到
* 队列中(因为存在一些从上次检查之后已经停止运行的线程或者加入这个方法之后线程池已经关闭)
* 所以我们重新检查了一下状态,如果有必要我们会回滚重新加入队列或者开启一个新的线程
*
* 3. 如果不能将任务添加到队列中,我们尝试创建一个新的线程,如果失败,就拒绝这个任务
*/
int c = ctl.get();
//如果线程数小于核心线程数,创建新线程,执行task
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
//如果失败了重新获取一下线程池的状态和线程的数量
c = ctl.get();
}
//workQueue.offer 可以插入返回true 不可以插入返回false
//如果正在运行 加入队列成功 需要重新检查一下状态
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
//如果不在运行 移除原来任务 拒绝任务
reject(command);
else if (workerCountOf(recheck) == 0)
//如果没有运行的线程,创建线程
addWorker(null, false);
}
else if (!addWorker(command, false))
//添加非核心线程失败直接拒绝
reject(command);
}
复制代码
执行流程图
复制代码
自定义线程池优化
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public class TestThreadPoolExecutor {
private static ThreadPoolExecutor threadPool = null;
static {
threadPool = new ThreadPoolExecutor(
3,
5,
30,
TimeUnit.MINUTES,
new ArrayBlockingQueue<Runnable>(5),
new TestThreadFactory(),
new TestRejectedExecutionHandler());
}
public static ExecutorService getCustomThreadPoolExecutor() {
return threadPool;
}
private static class TestThreadFactory implements ThreadFactory {
private AtomicInteger count = new AtomicInteger(0);
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
String threadName = TestThreadPoolExecutor.class.getSimpleName() + count.addAndGet(1);
System.out.println(threadName);
t.setName(threadName);
return t;
}
}
private static class TestRejectedExecutionHandler implements RejectedExecutionHandler {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
try {
//对于put方法,若向队尾添加元素的时候发现队列已经满了会发生阻塞一直等待空间,以加入元素。
System.out.println("runnable==exeception");
executor.getQueue().put(r);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void destory() {
if (threadPool != null) {
threadPool.shutdownNow();
}
}
}
复制代码
重点关注TestRejectedExecutionHandler,当队列满后会调用这个方法并抛弃该runable,可以监听这个方法来来处理相关逻辑。
Android中的使用
如上自定义的ThreadpoolExecutor处理队列满的方法executor.getQueue().put(r),该方法时线程阻塞的方法,如果在Android使用该处理异常的方法会回调到主线程中,直接导致app卡住,不建议使用阻塞的方法。