首页 > temp > 简明python教程 >
-
简单看看ThreadPoolExecutor原理
线程池的作用就不多说了,其实就是解决两类问题:一是当执行大量的异步任务时线程池能够提供较好的性能,在不使用线程池时,每当需要执行异步任务是需要直接new一个线程去执行,而线程的创建和销毁是需要花销的,而线程池中的线程是可复用的,不需要每次执行异步任务时都去创建和销毁线程;二是线程池提供了一种资源限制和管理的手段,比如可以限制线程的个数、动态新增线程等;
一.Executors工具类
我们创建一个线程池最好直接用这个工具类去创建,常用的线程池有几种,一种是用newFixedThreadPool方法创建固定大小的线程池,一种是newSingleThreadExecutor方法创建单线程的线程池,一种是newCachedThreadPool方法创建线程最多个数为Integer.MAX_VALUE的线程池,还有一些其他的线程池;
看一下Executors工具类中一些重要的方法,先是newFixedThreadPool方法,只看这个,我们可以实际的线程池类型是ThreadPoolExecutor,而且内部是以LinkedBlockingQueue这个并发队列实现的,前面说过,这是一个有界阻塞队列,底层是一个单向链表,入队和出队是用独占锁实现的一个生产者消费者模式,比较容易;
newSingleThreadExecutor方法,其实可以看到就是用上面的这种线程池实现的,只不过限制了线程池中线程必须只能是一个;
newCachedThreadPool方法,这种线程池也是以最上面的那种形式实现的,只不过限制了最大的数量是Integer.MAX_VALUE
由上面可知,三种其实都是以ThreadPoolExecutor实现的,所以我们了解这个类的实现机制就行了;
二.简单看看ThreadPoolExecutor结构
先看看其中的属性,比较多:
public class ThreadPoolExecutor extends AbstractExecutorService { //这个原子变量用于记录线程池的状态和其中线程的数量, //就类似读写锁里面一个int变量,高16位表示读锁的获取次数,低16位表示某一个线程获取写锁的可重入次数 //在线程池这里,高3位表示线程池状态,后面的29位表示线程池线程数量,默认线程池状态是RUNNING,线程数量为0 private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); //这里叫做线程个数掩码位数,举个例子,线程状态为STOP时,即1<<(32-3),也就是1<<29,用二进制表示00100000 00000000 00000000 00000000 //可以知道在原子变量中高3位是001 private static final int COUNT_BITS = Integer.SIZE - 3; //线程池中线程的最大容量,其实就是00011111 11111111 11111111 11111111 private static final int CAPACITY = (1 << COUNT_BITS) - 1; //高三位都是1,其他的29位都是0 private static final int RUNNING = -1 << COUNT_BITS; //都是0 private static final int SHUTDOWN = 0 << COUNT_BITS; //高三位是001,其他的29位都是0 private static final int STOP = 1 << COUNT_BITS; //高三位是010,其他的29位都是0 private static final int TIDYING = 2 << COUNT_BITS; //高三位是011,其他的29位都是0 private static final int TERMINATED = 3 << COUNT_BITS; //这里用位运算,取高三位,表示运行状态CAPACITY为:00011111 11111111 11111111 11111111 private static int runStateOf(int c) { return c & ~CAPACITY; } //取低29位,表示线程个数 private static int workerCountOf(int c) { return c & CAPACITY; } //这个方法用于计算原子变量ctl的值 private static int ctlOf(int rs, int wc) { return rs | wc; } //判断线程池状态是否是RUNNING,直接判断高三位是不是小于0就行了 private static boolean isRunning(int c) { return c < SHUTDOWN; } //CAS使得低29位加一,表示线程池中线程数量加一 private boolean compareAndIncrementWorkerCount(int expect) { return ctl.compareAndSet(expect, expect + 1); } //线程池中线程数量减一 private boolean compareAndDecrementWorkerCount(int expect) { return ctl.compareAndSet(expect, expect - 1); } //底层实现就是这个有界阻塞队列,前面已经说过这个队列的原理了,这个队列汇中存放的是实现了Runnable接口的任务 private final BlockingQueue<Runnable> workQueue; //独占锁用于控制添加Worker到集合workers中 private final ReentrantLock mainLock = new ReentrantLock(); //用于存放worker,这里封装着线程和任务 private final HashSet<Worker> workers = new HashSet<Worker>(); //条件变量 private final Condition termination = mainLock.newCondition(); //