首页 > 其他分享 >支付宝面试太太太刁钻了!!如果把线程池 corePoolSize 设置为 0,会出现什么情况?

支付宝面试太太太刁钻了!!如果把线程池 corePoolSize 设置为 0,会出现什么情况?

时间:2024-03-29 15:35:46浏览次数:27  
标签:JDK corePoolSize 面试 任务 线程 command 刁钻

大家好,我是R哥。

最近做 Java 面试辅导,有个学员面试支付宝,遇到一个特别有意思的问题:

如果把线程池 corePoolSize 设置为 0,会出现什么情况?

这个问题一说出来,我都感觉有点***钻。。

这几年我创作小程序:Java面试库,积累了 2700+ 的 Java 面试题,什么***钻的面试题没见过?

像这样的***钻面试题确实少见,阿里面试官是真的卷啊。。

大厂学员都觉得会抛异常,事实上真是这样吗?

我们来从源码来分析下,看看究竟!


先来回顾下线程池的工作流程:

1)如果线程池中的线程小于核心线程数 corePoolSize 时,则创建新线程直接执行任务。

2)如果线程池中的线程大于核心线程数 corePoolSize 时,则暂时把任务存储到工作队列 workQueue 中等待执行。

3)如果工作队列 workQueue 也满时:

  • 当线程数小于最大线程池数 maximumPoolSize 时,由创建新线程来处理;
  • 当线程数大于等于最大线程池数 maximumPoolSize 时,则执行拒绝策略;

更多参考我的更多 Java 多线程系列文章:https://www.javastack.cn/java/thread/


以下是 JDK 21 线程池类 ThreadPoolExecutor#execute 方法源码:

public void execute(Runnable command) {
    // 检查传入的任务是否为空,如果为空则抛出 NullPointerException
    if (command == null)
        throw new NullPointerException();

    // 获取当前线程池的控制状态
    int c = ctl.get();

    // 步骤 1: 如果当前运行的线程数少于核心线程数
    if (workerCountOf(c) < corePoolSize) {
        // 尝试添加一个新的工作线程来执行提交的任务
        // 如果添加成功,则直接返回
        if (addWorker(command, true))
            return;
        
        // 再次获取线程池的控制状态,以应对并发变化
        c = ctl.get();
    }

    // 步骤 2
    // 步骤 2.1: 如果线程池处于运行状态并且任务能够成功加入队列
    if (isRunning(c) && workQueue.offer(command)) {
        // 再次检查线程池的状态,确认线程池仍然处于运行状态
        int recheck = ctl.get();
        
        // 2.2 如果线程池不再运行,并且任务能够从队列中移除,则拒绝任务
        if (!isRunning(recheck) && remove(command))
            reject(command);
        
        // 2.3 如果当前线程池没有运行的线程
        else if (workerCountOf(recheck) == 0)
            // 尝试添加一个新的非核心工作线程(false 表示非核心线程)
            addWorker(null, false);
    }
    // 步骤 3
    else {
        // 3.1 尝试添加一个新的非核心工作线程来执行任务
        if (!addWorker(command, false))
            // 3.2 如果添加失败,说明线程池已关闭或达到饱和状态,因此拒绝任务
            reject(command);
    }
}

我检查了 JDK 8 和 JDK 17 两个主版本源码,这块的处理逻辑也是一样的。

从源码可以看到,如果往线程池提交任务的时候,当 corePoolSize = 0 时,代码正常情况下会执行到步骤2。

以下三步是关键步骤:

步骤 2.1:

此时,如果线程池处于运行状态,并且任务能够成功加入队列,说明线程池不为空,线程正常执行任务。

步骤 2.3:

此时,如果当前线程池没有运行的线程,则尝试添加一个新的非核心工作线程,即任务会先进入队列排队再由线程获取任务执行。

步骤 3.1:

此时,说明队列满了无法加入任务,尝试添加一个新的非核心工作线程来执行任务,如果添加失败,说明线程池已关闭或达到饱和状态,因此拒绝任务。

扩展知识点:

这个逻辑在 JDK 6 之前略有不同,在 JDK 6 之前,当 corePoolSize = 0 的时候,先将这个任务放到阻塞队列中,只有等队列满了才创建线程来执行,而 JDK 6+ 是直接创建一个非核心线程,再放在队列中来执行,很显示,JDK 6 这个优化动作减小了内存溢出的可能性。

光说 JDK 6 和 JDK 8 这两个版本,对线程池的重构就很大,现在主流的版本都是 JDK 8+,这个了解一下就好。


这道题可以说是八股文之王了,我工作这么多年,面试过这么多人,也没有见过这道题。

对于阿里这样的大厂,可能会遇到奇奇怪怪的问题,不会很正常,说说自己的想法,或许不会太减分。但如果你恰好看到了我的公众号,又学会了这道题,那下次有面试官问起,那就是加分题了,面试官也会对你眼前一亮。

像这样的面试八股文,我的小程序「Java面试库」还有许多,比如:

  • 为什么阿里不让用 Executors 创建线程池?
  • 线程池中的线程抛出了异常,如何处理?
  • ......

共 2700+,都是平时我面试别人,或者学员面试复盘积累下来的真题,不要在网上找乱七八糟的面试题了,浪费时间还容易被误导。

最后,推荐一波我的「面试辅导训练营」,有在看机会的,离职的、迷茫的,都可以加入我们的「面试辅导训练营」,大厂导师 1 v 1 辅导,帮你全面提升面试综合实力,少走很多弯路,最大化提升职场收益。

版权声明: 本文系公众号 "Java技术栈" 原创,转载、引用本文内容请注明出处,抄袭、洗稿一律投诉侵权,后果自负,并保留追究其法律责任的权利。

更多文章推荐:

1.Spring Boot 3.x 教程,太全了!

2.2,000+ 道 Java面试题及答案整理(2024最新版)

3.免费获取 IDEA 激活码的 7 种方式(2024最新版)

觉得不错,别忘了随手点赞+转发哦!

标签:JDK,corePoolSize,面试,任务,线程,command,刁钻
From: https://www.cnblogs.com/javastack/p/18103936

相关文章

  • 使用三个线程交替打印ABC
    //用的是线程、互斥锁、条件变量#include<iostream>#include<thread>#include<mutex>#include<condition_variable>usingnamespacestd;mutex_mutex; //定义锁变量condition_variablecv; //定义条件变量intflag=0; //切换线程的标识符,flag:0-2分别对应A......
  • 虚拟线程知识分享
    1相关概念-操作系统线程(operatingsystemthreads):即硬件设备配备的线程,一般和服务器硬件的核心数量,例如interCPU的大核拥有两个操作系统线程,小核拥有一个操作系统线程。云服务器的线程数一般和服务器配置上的核心数量相同。-平台线程(PaltformThread):java.lang.Th......
  • 线程池详解
    线程回顾创建一个线程需要做如下两件事:继承Thread实现RunnablepublicvoidTest(){ Threadthread=newThread(newMyrunnable());thread.start();}staticclassMyRunnableimplementsRunnable{@Overridepublicvoidrun(){......
  • 【Linux】线程同步{死锁/线程同步相关接口/由浅入深理解线程同步}
    文章目录1.死锁1.1概念1.2死锁的必要条件2.线程同步相关接口2.1pthread_cond_init/destroy()2.2intpthread_cond_wait2.3linux下的条件变量及其作用2.4intpthread_cond_signal/broadcast();2.5Linux下阻塞和挂起的异同2.6阻塞,挂起,和进程切换的关系3.由浅入深理解线......
  • 线程创建方式、构造方法和线程属性
    欢迎各位!!!推荐PC端观看文章重点:学会五种线程的创造方式目录1.开启线程的五种方式2.线程的构造方法3.线程的属性及获取方法1.开启线程的五种方式创造线程的基本两步:(1)使用run方法记录线程要做的任务(2)使用线程的引用调用start开启线程1.1.继承Tread,重写runclassm......
  • top命令找到占用CPU最高的java线程
    1、使用jps查找正在运行的java进程2、通过使用top命令查找该线程下CPU使用最高的线程top-Hppid:即  top-Hp2860 3、TIME列就是各个Java线程耗费的CPU时间,显然CPU时间最长的是ID为2968的线程,用printf"%x\n"2968可得到2968的十六进制值为:b984、终于轮到jsta......
  • "线程池中线程异常后:销毁还是复用?"
    一、一个线程池中的线程异常了,那么线程池会怎么处理这个线程?需要说明,本文的线程池都是java.util.concurrent.ExecutorService线程池,本文将围绕验证,阅读源码俩方面来解析这个问题。二、代码验证2.1验证execute提交线程池中2.1.1测试代码:publicclassThreadPoolEx......
  • java线程池原理浅析
     问题:查询大数据量的时候,例如一次返回50w数据量的包,循环去查询发现读取会超时。解决方案:经过思考采用多线程去分页查询。使用线程池创建多个线程去查询分页后的数据最后汇总一下,解决了一次查询大量数据返回超时的问题。一次查询现状:  多线程分页查询改造图: ......
  • 线程池的介绍与实现(多线程代码案例)
    目录概念:ThreadPoolExecutorintcorePoolSizeintmaximumPoolsizelongkeepAliveTimeTimeUnitunitBlockingQueuewokrQueueThreadthreadFactoryRejectedExecutionHandlerhandler1.ThreadPoolExecutor.Abortpolicy2.ThreadPoolExecutor.CallerRunsPolicy3.Thre......
  • 【Flutter 面试题】 Dart 是不是单线程模型?是如何运行的?
    【Flutter面试题】Dart是不是单线程模型?是如何运行的?文章目录写在前面口述回答补充说明示例:异步编程示例:使用Isolates处理计算密集型任务总结写在前面......