Java面经

1.队列是否一直存在?下一次定时任务是否要重新创建队列?

答:队列是否一直存在取决于队列是不是持久化的队列,如果是的话则一直存在不是的话就不是一直存在,比如说像rbmq,rocketmq这些中间件就是持久化存在的,启动时创建一次,然后就一直存在

java 复制代码
@Configuration
public class RabbitMqConfig {
    @Bean
    public Queue myTaskQueue() {
        // durable=true:持久化队列,Broker重启后仍存在
        return QueueBuilder.durable("task.queue").build();
    }
}

像定时任务内部的内存队列(如 ThreadPoolExecutor),@Async的异步线程池,它们都是属于jvm层面的,每次启动会创建,每次关闭会销毁。

即;

  • RabbitMQ 这类持久化中间件队列:创建后永久存在(除非手动删),仅首次启动创建一次,后续无需重建
  • JVM 内存队列(@Async / 定时任务线程池队列):项目关闭即销毁,每次项目启动都会重新创建(但启动后只创建一次,运行期间复用,不是每次执行任务都创建)
2.消费者的并发线程数是多少?

消费者并发线程数没有固定值,核心取决于业务场景、硬件资源、消息生产速度、消费逻辑耗时

  • 理论参考值:线程数 = CPU核心数 * (1 + 等待时间/计算时间)(阿姆达尔定律)。比如消费逻辑以 IO 等待(查 DB、调用接口)为主,等待时间远大于计算时间,线程数可设为 CPU 核心数的 2~4 倍;如果是纯内存计算,线程数接近 CPU 核心数即可。
  • 项目实操:比如基于 RocketMQ 的订单消费场景,服务器是 8 核 16G,消费逻辑需要调用支付接口(IO 密集),最终设置并发线程数为 16~24,同时配合流控、重试机制,避免线程过多导致上下文切换频繁或数据库连接池耗尽。
3.JVM 内存调优(堆大小、新生代 / 老年代分配)

调优前必须先通过工具(JVisualVM、Arthas、Prometheus+Grafana)分析GC 日志、内存快照(heap dump),明确问题(如频繁 Full GC、OOM、Young GC 耗时过长),而非盲目调参。

  • 观察 Young GC 频率:从原来的 1 分钟 / 次优化为 5 分钟 / 次,单次耗时从 200ms 降至 50ms 以内;
  • Full GC 频率:从原来的 1 小时 / 次降至 24 小时 / 次(仅凌晨低峰期出现);
  • 接口响应时间:P99 从 500ms 降至 150ms 以内。
4.对 MySQL 索引的了解及项目中的使用场景?

索引本质:MySQL 索引是帮助引擎快速获取数据的数据结构(B + 树为主),核心作用是减少磁盘 IO,提升查询效率。

核心类型:聚簇索引(主键索引)、二级索引(普通索引、唯一索引、联合索引)、全文索引等

索引一般有:B+树,hash索引,倒排索引,R树索引。

索引从存储方式又分为:聚簇索引和非聚簇索引。

聚簇索引: 聚簇索引是基于主键构建的索引(主键索引)

非聚簇索引: 非主键的那些字段(也是索引)

  • 一张表有很多棵 B+ 树

    • 1 棵 聚簇索引树(主键)
    • 每建一个普通索引,就多 1 棵 非聚簇索引树
  • **非聚簇索引树里存什么?**只存:

    • 索引字段的值
    • 主键 id不存其他数据。
  • 查询流程

    1. 先走 非聚簇索引树
    2. 找到对应的 主键 id
    3. 拿着 id 去 聚簇索引树
    4. 聚簇索引的 叶子节点存整行数据
  • 所有真实数据,只存在聚簇索引里

5.订单号长度不等时,索引如何处理?

订单号长度不等(比如有的是 16 位、有的是 20 位),只要订单号字段是字符串类型(VARCHAR/CHAR),创建索引依然生效,但需要注意:

  • 建议使用VARCHAR而非CHAR:CHAR 是定长,长度不等时会浪费存储空间;VARCHAR 是变长,仅存储实际长度 + 1 字节(长度标识);
  • 避免前缀截断:如果订单号长度差异大,不要盲目用前缀索引(如KEY idx_order_sn (order_sn(10))),除非能保证前缀的唯一性,否则会导致索引失效或回表次数增加;
  • 项目实操:订单表order_sn字段定义为VARCHAR(64),直接创建唯一索引UNIQUE KEY idx_order_sn (order_sn),即使长度不等,查询WHERE order_sn = 'xxx'依然能走索引,且效率不受影响。
6.可变字符串作为索引是否生效?会有什么问题?

订单号长度不等(比如有的是 16 位、有的是 20 位),只要订单号字段是字符串类型(VARCHAR/CHAR),创建索引依然生效,但需要注意:

  • 建议使用VARCHAR而非CHAR:CHAR 是定长,长度不等时会浪费存储空间;VARCHAR 是变长,仅存储实际长度 + 1 字节(长度标识);
  • 避免前缀截断:如果订单号长度差异大,不要盲目用前缀索引(如KEY idx_order_sn (order_sn(10))),除非能保证前缀的唯一性,否则会导致索引失效或回表次数增加;
  • 项目实操:订单表order_sn字段定义为VARCHAR(64),直接创建唯一索引UNIQUE KEY idx_order_sn (order_sn),即使长度不等,查询WHERE order_sn = 'xxx'依然能走索引,且效率不受影响。
7.联合索引的顺序与查询效率是否相关?

高度相关,核心遵循 "最左匹配原则":

  • 联合索引的顺序决定了查询是否能命中索引,以及索引的筛选效率;
  • 设计原则:区分度高的字段放前面(区分度 = 不同值的数量 / 总记录数)。
  • 示例:项目中订单表的联合索引idx_user_time (user_id, create_time)
    • 命中索引:WHERE user_id = 100 AND create_time > '2026-01-01'(全匹配)、WHERE user_id = 100(左前缀匹配);
    • 不命中索引:WHERE create_time > '2026-01-01'(跳过左前缀);
    • 效率差异:如果把区分度低的create_time放前面,索引筛选性差,比如WHERE create_time > '2026-01-01' AND user_id = 100,即使能通过优化器调整顺序,但索引树的结构依然低效,查询时需要扫描更多索引节点。
8.聚簇索引能否手动单独建立多个?

不能

  • 聚簇索引的核心特点:InnoDB 引擎中,聚簇索引的叶子节点直接存储整行数据,且一张表只能有一个聚簇索引
  • 默认规则:InnoDB 会优先以主键 作为聚簇索引;如果没有主键,会选择第一个唯一非空索引;如果都没有,会隐式创建一个 6 字节的row_id作为聚簇索引;
  • 注意:无法手动创建多个聚簇索引,因为这会导致数据存储结构混乱(整行数据无法同时存储在多个 B + 树的叶子节点),如果需要多维度查询,应创建二级索引(普通 / 联合索引),而非试图创建多个聚簇索引
相关推荐
Evand J1 小时前
matlab GUI制作界面的一些笔记(入门)
开发语言·笔记·matlab
Never_Satisfied1 小时前
在c#中,如何删除字符串中的第x个字符
开发语言·c#
_nirvana_w_2 小时前
Qt项目链接库时遇到的坑:-l选项的正确用法
开发语言·c++·qt·qt框架·elawidgettools
froginwe112 小时前
数据访问对象模式(Data Access Object Pattern)
开发语言
我命由我123452 小时前
Visual Studio - Visual Studio 修改项目的字符集
c语言·开发语言·c++·ide·学习·visualstudio·visual studio
Coder_Boy_2 小时前
Java高级_资深_架构岗 核心知识点全解析(模块四:分布式)
java·spring boot·分布式·微服务·设计模式·架构
百锦再2 小时前
Java ForkJoin 框架全面解析:分而治之的并行编程艺术
java·开发语言·spring boot·spring cloud·kafka·tomcat·maven
郝学胜-神的一滴2 小时前
Python变量本质:从指针哲学到Vibe Coding优化
开发语言·c++·python·程序人生