今天被这个问题整晕了,好好想了一下看了看源码才整清楚,看来以前还是没有理解的深入啊..稍微换个问法就晕了
线程池的基本流程
先弄清楚基本流程再去看部分实现细节
1如果运行的线程少于corePoolSize,则Executor始终首选添加新的线程,而不进行排队.
2如果运行的线程等于或多于corePoolSize,则 Executor 始终首选将请求加入队列,而不添加新的线程.
3如果无法将请求加入队列,则创建新的线程,除非创建此线程超出 maximumPoolSize,在这种情况下,任务将被拒绝.
这个流程一定要记清楚,这是最基本的流程啦
基本流程实现
我以JDK1.8中execute方法看看大体编码实现过程(略去部分细节)
execute方法可以看到execute方法就是对上面那三个流程的实现,这里就牵涉到另一个问题了,工作线程是如何工作的.下面继续看addWorker方法(这个方法太长了,我粘贴出来删去了部分)
addWorker方法基本流程相当简单,将当前任务作为firstTask参数丢给Worker对象,然后维护Worker对象的引用,最后start起来Worker线程.
下面看一下如何维护Worker列表的,就是一个HashSet对象....
维护Worker的列表
下面看Worker对象的实现
Worker对象
看一下runWorker方法,这就是最后的核心逻辑了
runWorker
大体的代码实现细节就是这样的流程了.
总结
总结一下实现细节收获
1线程池如何维护线程对象?
直接通过HashSet持有,Worker对象是在addWorker方法后被新建一个Thread对象运行(Thread对象start之后并没有直接持有,这个Thread被放到了Worker对象作为一个属性持有了),Worker对象的run方法中自己会去自旋取阻塞队列中的Runnable任务.我们只维护了Worker对象,启动Worker对象的线程就在Worker对象中持有.停止时就是遍历了Worker对象取出线程对象,然后调用停止方法等...
2如果新增任务时并未达到核心线程池大小,那么新加入的任务是否有可能会被其他Worker线程执行?
不会,新任务不会进入阻塞队列并且新建Worker线程要求传入FirstTask任务参数,也就是Worker线程会先执行当前加入进来的第一个任务,然后再去阻塞队列获取任务执行.
3阻塞队列的阻塞如何实现的
基础的通知等待模型就可以实现.也可以用ReentrantLock和Condition实现(ArrayBlockingQueue和LinkedBlockingQueue都是基于这个实现的),线程池已不关心实现细节了,只要求是个阻塞队列就可以
其他
深入细节还是要去看一下源码,理解了细节才可以描述清楚线程池的实现,这里记录一下方便以后迷糊的时候回来理解...也希望能帮助到迷糊的同学....
网友评论