3

线程池流程图

image.png

execute核心方法

image.png
这里不用多说,其实就是线程池的流程图中的所说的,如果小于核心线程数量,创建核心线程,否则往队列仍任务,假设队列也满了,那就创建非核心线程,如果大于了maximumPooSize,也就是说非核心线程也创建不了了,不好意思,那就走reject策略

addWorker

image.png
image.png
addWorker别看代码比较多,其实核心代码就是通过CAS来增加一个Worker count数,然后跳出循环,创建Worker加锁的方式加入到线程池中workers(HashSet)数据结构中,然后启动Worker

Worker

ThreadPoolExecutor创建了一个Worker并启动了他,我们是不是要看一下Worker是什么玩意?
image.png
唉吆喂,Worker竟然继承了AQS并实现了Runnable,加锁的线程,是不是?好吧,那既然是线程了,那看一下他run方法吧:
image.png
首先看看一下 task != null || (task = getTask()) != null,这个条件,对于第一次创建核心线程并执行run来说,firstTask是通过 w = new Worker(firstTask)传递过来,给了Worker实例变量了,所以task肯定是不为null的,同意吧?
然后看核心代码task.run,其实就是调用用户自己定义的run方法的逻辑,理解了吧

好了,那比如说我们核心线程的第一个任务运行完了呢?那getTask()就上场了:
image.png

其实有三部分核心逻辑 :

关闭线程池

如果已经对线程池进行了shutdown了,那好,等我workerQueue队列任务消费完毕,那我就线程退出
如果已经对线程池进行了stop,我去,好吧,你太暴力了,那就直接退出吧,会在shutdownNow中详细说

非核心线程超时

如果wc > corePoolSize,也就是说有非核心线程,是不是timed为true,然后非核心线程是以workQueue.poll以规定时间来获取任务,此时如果任务是null,没有任务,是不是timedOut=true了,好,然后再循环timed和timedOut都为true了,上述第二个逻辑的if就成立了,那非核心线程的Worker就会退出

阻塞和非阻塞方式获取任务

如果是核心线程,就会阻塞的方式take来拿任务,如果是非核心线程,就会进行poll(time)方式来拿任务

shutdonwNow & shutdown

  • shutdonwNow
    image.png
    advanceRunState(STOP):将线程池的状态改变为STOP,本质上是一个线程标记位的改变
    interruptWorkers():对线程池中的所有线程都进行终止(interrupt)操作
    image.png
    image.png
    这里会对所有的线程都会进行interrupt,那现在就有一个疑问,Worker会在哪里阻塞呢?其实有两处(Worker中):

    • 对于空闲的线程会在getTask中以take阻塞的方式来拿任务
    • 还有就是在task.run中,咱们自己定义业务逻辑如果有可中断的代码,就会被中断

    而shutdownNow会对所有的Worker进行interrupt,也可能会对正在运行的任务,如果可以响应中断,就会中断当前正在运行的任务,否则会进行下一次getTask的时候,即运行完当前任务,再下一次获取任务前判断退出Worker线程

  • shutdown
    image.png
    interruptIdleWorkers:是interrupt空闲的线程,谁是空闲的线程?怎么来区分,这里AQS就出场了
    image.png
    w.tryLock()是一个很关键的玩意,要知道,如果Worker正在执行任务,正在执行task.run(),这前面肯定是加锁的,所以tryLock是拿不到锁的,所以针对正在运行的Worker线程是不interrupt的

如感兴趣,点赞加关注,谢谢


journey
32 声望21 粉丝

« 上一篇
事务原理总结
下一篇 »
设计模式

引用和评论

0 条评论