档案网站建设经验,企业黄页名单,下载共富工程app软件安装包,台州网站建设开发文章目录零、引入一、王二的新坑#xff1a;只知用 Executors#xff0c;不知 ThreadPoolExecutor➡️ ThreadPoolExecutor 的 “命脉”#xff1a;7 个核心参数二、ThreadPoolExecutor 工作原理#xff1a;流水线怎么处理零件#xff1f;#x1f449; 工作流程✔️ 拒绝…文章目录零、引入一、王二的新坑只知用 Executors不知 ThreadPoolExecutor➡️ ThreadPoolExecutor 的 “命脉”7 个核心参数二、ThreadPoolExecutor 工作原理流水线怎么处理零件 工作流程✔️ 拒绝策略料箱满了怎么办面试高频三、实战自定义 ThreadPoolExecutor掌控一切四、面试高频题ThreadPoolExecutor 核心问题附答案➡️ 面试题 1ThreadPoolExecutor 的 corePoolSize 和 maximumPoolSize 有什么区别怎么设置 面试题 2ThreadPoolExecutor 的任务队列有哪些选择分别用在什么场景✅ 面试题 3为什么不推荐用 Executors 创建线程池五、总结ThreadPoolExecutor 核心心法王二编的顺口溜❓ 哇哥的血泪教训 作者: 编程技术圈(哇哥面试陪跑) 欢迎关注、分享、评论✔️ 持续分享更多干货内容➕tcmeta, 欢迎沟通交流零、引入王二从面试间出来脸比锅底还黑。面试官最后抛了个问题“ThreadPoolExecutor 的核心参数有哪些工作原理是什么” 他支支吾吾只说出个 “核心线程数”后面的全卡壳了 —— 心仪的岗位就这么飞了。回到工位哇哥正对着一份线程池监控报表皱眉见王二这模样便知是怎么回事。“ThreadPoolExecutor 是 Executor 框架的骨头面试必考你连骨头都没啃动怎么能过” 哇哥把报表推到他面前“今天用车间流水线的道理把这东西讲透下次再被问你就把面试官说懵。”点赞 关注跟着哇哥和王二吃透 ThreadPoolExecutor 的核心并发面试的半壁江山就稳了一、王二的新坑只知用 Executors不知 ThreadPoolExecutor王二之前用 Executor全靠 Executors 工具类比如Executors.newFixedThreadPool(10)从来没深究过背后的 ThreadPoolExecutor。面试官一追问 “FixedThreadPool 的核心参数怎么设置的”他就露怯了。“Executors 是给新手用的拐杖” 哇哥嗤笑一声“它帮你封装了 ThreadPoolExecutor 的参数但生产环境里这拐杖迟早把你绊倒。你得知道 ThreadPoolExecutor 的构造方法那才是真东西。”➡️ ThreadPoolExecutor 的 “命脉”7 个核心参数哇哥打开 JDK 源码指着 ThreadPoolExecutor 的构造方法// ThreadPoolExecutor的核心构造方法publicThreadPoolExecutor(intcorePoolSize,// 核心线程数intmaximumPoolSize,// 最大线程数longkeepAliveTime,// 非核心线程空闲时间TimeUnitunit,// 空闲时间单位BlockingQueueRunnableworkQueue,// 任务队列ThreadFactorythreadFactory,// 线程工厂RejectedExecutionHandlerhandler// 拒绝策略){// ... 初始化逻辑}“这 7 个参数就是车间的‘管理制度’” 哇哥拿车间流水线类比一下就把抽象参数讲活了王二恍然大悟“原来 newFixedThreadPool (10)就是把 corePoolSize 和 maximumPoolSize 都设为 10相当于车间全是正式工没有临时工”“总算开窍了” 哇哥点头“Executors.newFixedThreadPool (n) 的底层就是 new ThreadPoolExecutor (n, n, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue())——它帮你填了参数但你得知道填的是什么。”二、ThreadPoolExecutor 工作原理流水线怎么处理零件“知道了参数还得懂工作流程” 哇哥拿一支笔当零件在桌上演示“当一个任务零件过来流水线线程池是这么处理的先看正式工(核心线程) 有没有空有空就安排正式工干正式工都忙了就把零件放进料箱任务队列料箱也满了就招临时工非核心线程来干正式工 临时工都满了料箱也满了就执行拒绝策略比如告诉送零件的‘别送了放不下了’。” 工作流程✔️ 拒绝策略料箱满了怎么办面试高频哇哥强调“拒绝策略是面试必问就像料箱满了车间总得有个说法。JDK 默认提供 4 种拒绝策略”AbortPolicy默认直接抛RejectedExecutionException异常简单粗暴CallerRunsPolicy让提交任务的线程自己执行比如送零件的人自己动手干缓解压力DiscardPolicy悄悄丢弃任务不抛异常风险高慎用DiscardOldestPolicy丢弃队列里最老的任务再把新任务加进去。“生产环境里别用默认的 AbortPolicy”哇哥提醒“比如秒杀场景任务满了直接抛异常用户体验太差用 CallerRunsPolicy 或者自定义拒绝策略比如记录日志返回‘系统繁忙请重试’更友好。”三、实战自定义 ThreadPoolExecutor掌控一切王二照着哇哥的指导写了个自定义线程池的代码把 7 个参数都配置了一遍还加了自定义拒绝策略packagecn.tcmeta.threadpoolexecutor;importjava.util.concurrent.*;/** * author: laoren * description: 自定义ThreadPoolExecutor生产环境可用 * version: 1.0.0 */publicclassCustomThreadSample{staticvoidmain(){// 1. 核心参数配置intcorePoolSize5;// 正式工5人intmaximumPoolSize10;// 最多10人5正式5临时longkeepAliveTime60;// 临时工空闲60秒解雇TimeUnitunitTimeUnit.SECONDS;// 时间单位秒// 2. 任务队列容量100的阻塞队列BlockingQueueRunnableworkQueuenewLinkedBlockingQueue(100);// 3. 线程工厂给线程命名便于排查问题ThreadFactorythreadFactorynewThreadFactory(){privateintcount0;OverridepublicThreadnewThread(Runnabler){ThreadthreadnewThread(r);thread.setName(order-thread-(count));// 线程名订单处理线程-1returnthread;}};// 4. 自定义拒绝策略记录日志返回友好提示RejectedExecutionHandlerrejectedHandler(r,executor)-{// 记录任务拒绝日志System.out.println(任务r.toString()被拒绝当前线程池状态核心线程数executor.getCorePoolSize()活跃线程数executor.getActiveCount()队列任务数executor.getQueue().size());// 实际项目中可以抛自定义异常让上层返回“系统繁忙”thrownewRejectedExecutionException(系统繁忙请稍后重试);};// 5. 创建自定义线程池try(ThreadPoolExecutorthreadPoolnewThreadPoolExecutor(corePoolSize,maximumPoolSize,keepAliveTime,unit,workQueue,threadFactory,rejectedHandler);){// 6. 提交任务模拟120个订单任务for(inti0;i120;i){intorderIdi;threadPool.submit(()-{try{TimeUnit.MILLISECONDS.sleep(100);// 模拟处理订单耗时System.out.println(Thread.currentThread().getName()处理订单orderId完成);}catch(InterruptedExceptione){Thread.currentThread().interrupt();}});}// 7. 关闭线程池threadPool.shutdown();}}}王二看着清晰的线程名和拒绝日志感慨道“这下出了问题我能直接定位到是‘订单处理线程’的问题比之前的 Thread-1 好多了”“这就是自定义线程池的好处” 哇哥说“线程命名、拒绝策略、队列容量全在你掌控之中生产环境出问题也能快速排查。”四、面试高频题ThreadPoolExecutor 核心问题附答案哇哥整理了 3 道面试必考题王二抄在小本本上背得滚瓜烂熟➡️ 面试题 1ThreadPoolExecutor 的 corePoolSize 和 maximumPoolSize 有什么区别怎么设置答案区别corePoolSize 是核心线程数正式工即使空闲也不销毁maximumPoolSize 是核心线程 非核心线程的总数正式工 临时工非核心线程空闲到 keepAliveTime 会销毁。设置依据:CPU 密集型任务比如计算核心线程数 CPU 核心数 1避免线程切换开销IO 密集型任务比如调用接口、查数据库核心线程数 CPU 核心数 * 21因为线程大部分时间在等 IO多开线程能提高利用率。 面试题 2ThreadPoolExecutor 的任务队列有哪些选择分别用在什么场景答案常用的阻塞队列有 3 种LinkedBlockingQueue链表队列无界队列默认适合任务量稳定的场景但任务过多会导致 OOMArrayBlockingQueue数组队列有界队列适合控制任务数量的场景配合拒绝策略使用避免 OOMSynchronousQueue同步队列零容量队列任务必须马上被线程处理适合实时性要求高的场景比如秒杀对应 Executors.newCachedThreadPool ()。✅ 面试题 3为什么不推荐用 Executors 创建线程池Executors 封装的线程池有 3 个致命问题生产环境慎用newFixedThreadPool/newSingleThreadExecutor用 LinkedBlockingQueue无界队列任务过多会导致 OOMnewCachedThreadPoolmaximumPoolSize是 Integer.MAX_VALUE任务过多会创建大量线程导致 OOMnewScheduledThreadPool核心线程数固定任务队列无界同样有 OOM 风险。解决方案用 ThreadPoolExecutor 自定义线程池手动设置核心参数、有界队列和拒绝策略。五、总结ThreadPoolExecutor 核心心法王二编的顺口溜七参数是命脉流水线来类比核心线程是正式工最大线程含临时队列是料箱满了招临时拒绝策略要选好用户体验差不了Executors 是拐杖自定义才是真章。❓ 哇哥的血泪教训“我刚工作时用 Executors.newCachedThreadPool 处理日志” 哇哥回忆道“有次系统出 bug日志量暴增线程池创建了几千个线程JVM 直接 OOM 挂了。后来换成自定义线程池队列设为 1000拒绝策略用 CallerRunsPolicy就算日志再多也不会把系统拖垮 —— 这都是血的教训。”关注我下一篇咱们扒一扒 Executor 框架的实战优化 —— 怎么用 Executor 处理批量任务线程池怎么监控生产环境里怎么防止线程池 “雪崩”让你不仅会用 Executor还能用得稳、用得好成为并发领域的老手