news 2026/4/15 1:14:21

Java八股,高频知识点

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java八股,高频知识点

一、Java 并发编程

Java 并发编程 = 让程序同时做多件事,并保证数据不出错。

1、线程池的核心参数和原理

Java 的ThreadPoolExecutor为例,有 7 个核心参数:

参数说明
corePoolSize核心线程数⭐
maximumPoolSize最大线程数⭐
keepAliveTime非核心线程空闲存活时间
unit存活时间的单位
workQueue任务等待队列⭐
threadFactory线程工厂(用于创建线程)
handler拒绝策略(队列和线程池都满时)⭐

执行流程如下:

拒绝策略(4种内置)

策略行为
AbortPolicy(默认)直接抛出RejectedExecutionException
CallerRunsPolicy由调用者线程自己执行任务
DiscardPolicy静默丢弃任务
DiscardOldestPolicy丢弃队列头部的任务,重新提交当前任务

创建一个线程池

ThreadPoolExecutor executor = new ThreadPoolExecutor( 2, // corePoolSize 5, // maximumPoolSize 60L, // keepAliveTime TimeUnit.SECONDS, // unit new LinkedBlockingQueue<>(10), // 基于链表的阻塞队列,容量为 10 Executors.defaultThreadFactory(), // 线程工厂 new ThreadPoolExecutor.AbortPolicy() // 拒绝策略 ); // 60L 中的 L 表示这是一个 long 类型的字面量 // SECONDS是存活时间单位,因此非核心线程的空闲存活时间为 60 秒

常见误区

  • 队列满后才创建非核心线程(很多人误以为超过 core 就立刻创建)

  • 核心线程也可以被回收:设置allowCoreThreadTimeOut(true)后,核心线程空闲超时也会被回收

  • Executors工厂方法有风险

    • newFixedThreadPool:队列无限,可能导致 OOM

    • newCachedThreadPool:最大线程数无限,高并发时可能创建大量线程

2、IO密集型和CPU密集型的线程池配置

两者的核心区别在于:线程等待的时间占比不同,因此最佳线程数也不同。

简化公式:

CPU密集型:线程数 = CPU核心数 + 1 IO密集型:线程数 = CPU核心数 × 2 (或更多)

CPU密集型

特点:任务主要消耗CPU(计算、加密、排序、循环等),线程很少等待

配置原则:线程数 ≈ CPU核心数,避免过多线程导致频繁上下文切换

int coreCount = Runtime.getRuntime().availableProcessors(); ThreadPoolExecutor cpuPool = new ThreadPoolExecutor( coreCount, // 核心线程 = CPU核心数 coreCount + 1, // 最大线程 = 核心数+1(留一个余量) 10L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(100), // 用有界队列,防止任务堆积过多 Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy() );

推荐配置

  • corePoolSize= CPU核心数

  • maximumPoolSize= CPU核心数 + 1

  • 队列大小适中(几百即可)

为什么+1?:即使某个线程因页缺失等短暂阻塞,仍有备用线程继续利用CPU。


IO密集型

特点:任务主要等待IO(数据库查询、HTTP调用、文件读写、网络请求等),CPU大部分时间空闲。

配置原则:线程数可以远大于CPU核心数,让CPU在等待期间去处理其他线程。

int coreCount = Runtime.getRuntime().availableProcessors(); // 方法1: 2倍核心数 ThreadPoolExecutor ioPool1 = new ThreadPoolExecutor( coreCount * 2, // 核心线程 = 2倍核心数 coreCount * 4, // 最大线程 = 4倍核心数 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(200), Executors.defaultThreadFactory(), new ThreadPoolExecutor.CallerRunsPolicy() // 用CallerRunsPolicy削峰 ); // 方法2:更精确的计算(假设IO耗时是CPU的10倍) // 最佳线程数 = CPU核心数 × (1 + 等待时间 / 计算时间) // 线程数 = 核心数 × (1 + 10) = 核心数 × 11 int exactThreads = coreCount * (1 + (ioTime / cpuTime));

推荐配置

  • corePoolSize= CPU核心数 × 2~4

  • maximumPoolSize= CPU核心数 × 4~8

  • 队列可以稍大,但要有限界防止OOM


对比总结

维度CPU密集型IO密集型
线程数
corePoolSizeN_cpuN_cpu × 2~4
maximumPoolSizeN_cpu + 1N_cpu × 4~8
keepAliveTime较短(秒级)较短(秒级)
队列有界,适中有界,可稍大
拒绝策略AbortPolicyCallerRunsPolicy(削峰)

CallerRunsPolicy : 由调用者线程自己执行任务

怎么理解:任务提交给线程池,但线程池满了 → 不抛异常、不丢弃任务,而是让 “提交任务的那个线程自己去 run 这个任务”

3、无界队列会导致什么问题?

常见队列类型对比

队列类型特点容量
LinkedBlockingQueue()无界队列,可以无限存任务Integer.MAX_VALUE
LinkedBlockingQueue(10)有界队列,最多存 10 个固定大小
ArrayBlockingQueue(10)基于数组的有界队列固定大小
SynchronousQueue()不存任务,直接交给线程容量为 0

注意:如果用new LinkedBlockingQueue()(不指定容量),队列无界,线程数永远不会超过corePoolSize,而maximumPoolSize参数失效


使用线程池创建无界队列new LinkedBlockingQueue()(不指定容量)或new LinkedBlockingQueue(Integer.MAX_VALUE)会导致以下严重问题:


1.内存溢出(OOM)最严重

当任务生产速度>消费速度时,队列会无限堆积,直到耗尽内存:

// 危险示例 ThreadPoolExecutor pool = new ThreadPoolExecutor( 2, 10, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>() // 无界队列! ); // 疯狂提交任务(比如每秒1000个,处理能力只有200个/秒) for (int i = 0; i < Integer.MAX_VALUE; i++) { pool.execute(() -> { Thread.sleep(1000); // 任务慢 }); } // 结果:内存持续增长 → OOM → 程序崩溃

2. maximumPoolSize 参数失效

核心机制回顾:只有队列满时才会创建新线程(直到达到 max)

ThreadPoolExecutor pool = new ThreadPoolExecutor( 2, 10, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(), // 无界队列,永远不满 new ThreadPoolExecutor.AbortPolicy() ); // 提交10000个任务 // 结果:始终只有2个线程在工作,其他8个线程永远不会被创建

因为无界队列永远不会满,所以永远不触发创建非核心线程的逻辑。


3.响应时间不可预测

任务积压导致:

  • 延迟从毫秒级 → 秒级 → 分钟级

  • 超时问题:依赖方等不及,上游服务报错

  • 用户体验极差


4. 故障难以排查

  • 系统变慢,但没有报错(无界队列不会抛拒绝异常)

  • 你以为是代码问题,实际上是队列积压

  • 内存缓慢增长,可能几天后才 OOM

排查困难:没有明显的异常堆栈,只有性能下降。


对比示例

场景有界队列 (capacity=10)无界队列
提交速度 > 处理速度队列满后抛异常或触发拒绝策略队列无限增长 → OOM
最大线程数会创建到 max(队列满时)永远不会超过 core(队列永不满足)
问题发现立即抛异常,快速失败慢慢变慢,几天后崩溃
适用场景生产环境几乎不适用

什么情况下可以用无界队列?

极少场景

  1. 任务提交速度稳定且远小于处理速度

  2. 核心线程数足够大(等同于最大线程数)

  3. 内存足够大 + 监控完善

    • 定时监控队列大小,超过阈值告警

    • 仍是风险较高的设计

4、空闲线程回收机制?

线程池中的空闲线程回收主要针对非核心线程,核心线程默认不会被回收,但也可以配置回收。


1. 非核心线程的回收

触发条件

当线程空闲时间超过keepAliveTime时被回收。

工作原理

ThreadPoolExecutor pool = new ThreadPoolExecutor( 2, // 核心线程数 5, // 最大线程数 60L, // 空闲存活时间 TimeUnit.SECONDS, // 单位:秒 new LinkedBlockingQueue<>(10) ); // 场景:创建了5个线程(2核心+3非核心) // 任务执行完后,非核心线程空闲超过60秒 → 被回收 // 核心线程(2个)不会被回收,一直存活

回收过程

任务执行完毕 ↓ 线程从队列获取新任务 poll(keepAliveTime, unit) ↓ 等待keepAliveTime时间 ↓ 没等到新任务 → 超时返回null ↓ 线程判断:当前线程数 > corePoolSize? ↓ 是 该线程被回收(终止)

关键方法poll(time, unit)会在超时后返回null,触发线程退出。


2. 核心线程的回收

默认情况下,核心线程不会被回收,即使空闲很长时间。

开启核心线程回收

// 设置 allowCoreThreadTimeOut(true) pool.allowCoreThreadTimeOut(true); // 效果:核心线程空闲超过 keepAliveTime 也会被回收

回收时机总结

线程类型默认行为可配置行为
核心线程永不回收通过allowCoreThreadTimeOut(true)回收
非核心线程空闲超过keepAliveTime后回收同上

5、workQueue的作用,队列满了为什么先入队而不是先扩容线程?

这是一个很好的设计问题。队列先满才扩容ThreadPoolExecutor的核心设计决策,主要基于以下考虑:


核心原因:线程是昂贵资源

线程创建成本高

  • 创建线程需要分配栈内存(默认1MB)

  • 涉及操作系统系统调用

  • 线程切换有上下文切换开销

队列存储成本低

  • 队列中的任务只是对象引用

  • 不创建新线程,开销极小

设计原则:能用便宜的队列缓冲,就不用昂贵的线程资源。


什么时候会先扩容?

有一个例外:SynchronousQueue

// 使用 SynchronousQueue(容量为0) ThreadPoolExecutor pool = new ThreadPoolExecutor( 2, 10, 60L, TimeUnit.SECONDS, new SynchronousQueue<>() // 队列容量为0 );

行为变化

  • 队列容量为0 →offer()总是立即返回false(除非有消费者在等)

  • 实际上变成:直接创建非核心线程(没有"先入队"这一步)

这等同于先扩容,适合任务需要立即执行、不能等待的场景。


总结

问题答案
为什么先入队?队列比线程便宜得多
什么场景下先扩容?使用SynchronousQueue
什么场景适合先入队?有波峰波谷的通用场景
什么场景需要先扩容?延迟极度敏感、任务必须立即执行
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/15 1:13:21

生成对抗网络 GAN 基础:对抗训练原理

文章目录前言一、GAN到底是个啥&#xff1f;一句话一个神类比1.1 官方定义&#xff08;一句话&#xff09;1.2 神类比&#xff1a;造假大师 vs 鉴宝专家1.3 为什么叫“对抗网络”&#xff1f;不是“合作网络”&#xff1f;二、GAN核心结构&#xff1a;两大组件&#xff0c;分工…

作者头像 李华
网站建设 2026/4/15 1:00:25

​[特殊字符]1 概述双机并联逆变器自适应虚拟阻抗下垂控制策略研究摘要孤岛型微电网中,逆变器双机并联运行是提升供电可靠性的核心拓扑结构之一,传统下垂(Droop)控制因未考虑线路阻抗不匹配问题

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

作者头像 李华
网站建设 2026/4/15 0:54:03

对抗攻击防御超简单

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 让对抗防御不再高不可攀&#xff1a;教育化工具与轻量级部署的融合实践目录让对抗防御不再高不可攀&#xff1a;教育化工具与轻量…

作者头像 李华
网站建设 2026/4/15 0:51:14

终极AMD处理器调试指南:全面掌握硬件性能调优技巧

终极AMD处理器调试指南&#xff1a;全面掌握硬件性能调优技巧 【免费下载链接】SMUDebugTool A dedicated tool to help write/read various parameters of Ryzen-based systems, such as manual overclock, SMU, PCI, CPUID, MSR and Power Table. 项目地址: https://gitcod…

作者头像 李华
网站建设 2026/4/15 0:50:55

2025届最火的六大AI辅助写作网站横评

Ai论文网站排名&#xff08;开题报告、文献综述、降aigc率、降重综合对比&#xff09; TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 人工智能技术已经深度地渗透到了毕业论文写作的整个过程之中&#xff0c;在选题的阶段&#…

作者头像 李华