持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第30天,点击查看活动详情
ThreadPoolExecutor线程池执行器
使用ThreadPoolExecutor线程池代码如下:
public class ThreadPoolExecutorRun {
public static void main(String[] args) {
//创建一个核心线程数为1,最大线程数为1,无界队列的线程池
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 0, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
//向线程池提交任务
threadPoolExecutor.submit(()->{
System.out.println("Gxin"+System.currentTimeMillis());
});
//关闭线程池
threadPoolExecutor.shutdown();
//等待线程池终止
try {
threadPoolExecutor.awaitTermination(1,TimeUnit.HOURS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
ThreadPoolExecutor核心数据结构
ThreadPoolExecutor的核心数据结构和变量如下:
public class ThreadPoolExecutor extends AbstractExecutorService {
//通过一个原子性的integer整型值包含了workerCount工作线程数和runState运行状态
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
//统计数量位数COUNT_BITS:32-3=29,所以最大工作线程数为CAPACITY:2^29 - 1,大约有5亿个,足够使用了。
private static final int COUNT_BITS = Integer.SIZE - 3;
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
//上面的一个整数为32位,占用了29位统计数量,剩下的3位高位bit用来作为线程池状态。
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;
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; }
private final BlockingQueue<Runnable> workQueue;
private final ReentrantLock mainLock = new ReentrantLock();
private final HashSet<Worker> workers = new HashSet<Worker>();
}
解析方法如下:
runState提供了主要的生命周期控件,线程运行的状态变化,其值如下:
RUNNING:接收新任务并处理排队的任务。
SHUTDOWN:不接收新任务,但处理已排队的任务。
STOP:不接收新任务,不处理排队的任务,中断正在进行的任务。
TIDYING:所有的任务已经停止,workerCount为零,当线程过渡到TIDYING状态时,将运行terminated()钩子方法。
TERMINATED:TERMINATED()已经执行完成。
runStateOf(int c)、workerCountOf(int c)、ctlOf(int rs, int wc):3个函数用来从ctl整型变量中获取对应的状态或者线程数。
workQueue:用于缓存提交到线程池的任务队列,注意点是队列类型是BlockingQueue,证明了多线程操作是安全的,毕竟是生产者消费者模式,外部线程producer,内部线程consumer。
ReentrantLock():用于保护全局互斥资源的可重入锁。
new HashSet()方法:用于保存所有线程池中的Worker对象的set集合,可以看出这并不是线程安全的结构,所以在多线程中访问这个集合需要通过上面的mainLock上锁后访问,保证线程安全。