• 面试--线程池的执行流程和拒绝策略有哪些?


    一. 执行流程

    聊到线程池就一定会聊到线程池的执行流程, 也就是当有一个任务进入线程池之后, 线程池是如何执行的?

    想要真正的了解线程池的执行流程,就得先从线程池的执行方法 execute() 说起, execute() 实现源码如下: 

    1. public void execute(Runnable command) {
    2. if (command == null) {
    3. throw new NullPointerException();
    4. }
    5. int c = ctl.get();
    6. // 当前工作的线程数小于核心线程数
    7. if (workerCountOf(c) < corePoolSize) {
    8. // 创建新的线程执行此任务
    9. if (addWorker(command, true)) {
    10. return;
    11. }
    12. c = ctl.get();
    13. }
    14. // 检查线程池是否处于运行状态,如果是则把任务添加到队列
    15. if (isRunning(c) && workQueue.offer(command)) {
    16. int recheck = ctl.get();
    17. // 再次检线程池是否处于运行状态,防止在第一次校验通过后线程池关闭
    18. // 如果是非运行状态,则将刚加入队列的任务移除
    19. if (! isRunning(recheck) && remove(command)) {
    20. reject(command);
    21. }
    22. // 如果线程池的线程数为 0 时(当 corePoolSize 设置为 0 时会发生)
    23. else if (workerCountOf(recheck) == 0) {
    24. addWorker(null, false); // 新建线程执行任务
    25. }
    26. }
    27. // 核心线程都在忙且队列都已爆满,尝试新启动一个线程执行失败
    28. else if (!addWorker(command, false)) {
    29. // 执行拒绝策略
    30. reject(command);
    31. }
    32. }

    线程池的工作流程

    总结

    线程池的执行流程有 3 个重要的判断点:

    1. 判断当前线程数和核心线程数.
    2. 判断当前任务队列是否已满.
    3. 判断当前线程数是否已达最大线程数.

    如果在经过上诉三个过程后, 得到的结果都是 true , 那么就会执行线程池的拒绝策略.

    二. 拒绝策略

    当任务过多且线程池的任务队列已满时, 此时就会执行线程池的拒绝策略, 线程池的拒绝策略默认有以下 4 种: 

    1. AbortPolicy:中止策略,线程池会抛出异常并中止执行此任务.
    2. CallerRunsPolicy:把任务交给添加此任务的(main)线程来执行.
    3. DiscardPolicy:忽略此任务,忽略最新的一个任务.
    4. DiscardOldestPolicy:忽略最早的任务,最先加入队列的任务.

    在分析JDK自带的线程池拒绝策略前,先看下JDK定义的 拒绝策略接口:

    1. public interface RejectedExecutionHandler {
    2. void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
    3. }

    接口定义大概就是, 当触发拒绝策略时, 线程池会根据你设置的具体的策略, 将当前提交的任务以及线程池实例本身传递给你处理, 具体作何处理, 不同场景会有不同的考虑.

    1. AbortPolicy(中止策略)

    功能: 当触发拒绝策略时,直接抛出拒绝执行的异常,中止策略的意思也就是打断当前执行流程

    2. CallerRunsPolicy(调用者运行策略)

    功能:当触发拒绝策略时,只要线程池没有关闭,就由提交任务的当前线程处理.

    3. DiscardPolicy(丢弃策略)

    功能:直接静悄悄的丢弃这个任务,不触发任何动作.

    4. DiscardOldestPolicy(弃老策略)

    功能:如果线程池未关闭,就弹出队列头部的元素,然后尝试执行.

  • 相关阅读:
    实现 JSON.parse
    【机器学习笔记】【决策树】【泰坦尼克号幸存者的预测】
    springboot毕设项目慈善公益平台30938(java+VUE+Mybatis+Maven+Mysql)
    硬件学习件Cadence day14 器件TOP 层和 BOTTOM 层都有贴片怎么设计
    Linux应急响应
    小红书笔记详情API:挖掘小红书社区的秘密宝藏
    [LeetCode解题报告] 1610. 可见点的最大数目
    黑马程序员微服务Docker实用篇
    内存条选购注意事项(电脑,笔记本)
    ch12、字符串(string)与字符编码
  • 原文地址:https://blog.csdn.net/qq_52592775/article/details/127886933