从数据结构开始,了解线程池的设计
-
ctl 《AtomicInteger》 线程池核心控制字段
-
mainLock 《ReenTtranLock》:当执行HashSet《Worker》的插入、移除等操作时,由于他不是线程安全的,所以需要mainLock加锁
-
BlockingQueue《Runnable》任务队列,worker会从blockingQueue中不断获取任务,然后执行
-
workers = HashSet《Worker》,worker表示线程池的基本工作单元
-
Worker,线程池基本工作单元
- 实现与继承
-
继承《extends》 AQS
- 编写lock方法,当worker执行lock方法时,表明当前的worker正在执行task任务,task任务的来源为blockingQueue
- 编写unLock方法,执行完unLock方法,worker进入空闲状态
当线程池执行stop方法时,会循环hashSet中所有的worker,获取他们是否处于加锁状态,直到所有的worker都处于空闲状态时,才会最终终止线程池
-
实现《implements》Runnable,实现了run方法
-
- 类结构
- firstTask《Runnable》创建Worker时,即线程池执行execute方法时,本身会传入一个task
- thread,工作线程,用于执行runnable任务
- 实现与继承
执行逻辑
说明:执行逻辑准备分三个部分进行介绍,一部分是主流程,即ThreadPoolExecutor的execute方法;第二部分是worker执行流程;
- ThreadPoolExecutor#execute
-
核心线程数、最大线程数,表示的都是HashSet《Worker》中的worker的数量,用ctl的低28位记数
-
在执行execute方法时,指定入参task《Runnable》;如下图,当需要增加Worker时,需要创建Worker对象,过程如下:
- 重要:::通过内部的TreadFactory创建线程,需要指定一个Runnable,前面我说过,Worker实现了Runnable,所以此处创建的线程,指定的runnable是worker本身
Worker(Runnable firstTask) { setState(-1); // inhibit interrupts until runWorker this.firstTask = firstTask; this.thread = getThreadFactory().newThread(this); }
- 使用mainLock加锁,然后将worker添加到HashSet《Worker》中
- 添加完成后,执行 worker.thread.start(),启动线程
- 线程启动后,会自动执行worker的run方法,具体内容后面会继续介绍
- mainLock解锁
-
- Worker的run方法执行过程,核心的执行逻辑
- run方法内部,是一个while(true)的轮询,不断的从blockingQueue中获取task,执行。
- aqs的作用:worker加锁,表明worker这个工作单元正在执行任务,解锁后,表示处于空闲状态