2025 年 Java 常见面试题
数据库事务特性。原子性、一致性、隔离性、持久性
如何防止SQL注入:使用 #不要使用 $符号;对所有的入参做校验;使用存储过程;执行预处理语句和参数化查询;最低权限原则;
微服务拆分的原则:微服务的拆分应该从业务、技术、组织结构三个维度进行考虑。业务上按照DDD领域驱动设计原则来进行拆分,然后根据持续演进原则先粗后细逐步的进行迭代。
技术上按照单一责任、闭包、服务自治、高内聚低耦合、数据隔离原则进行拆分,也需要考虑性能问题将性能要求高或性能压力大的服务单拆出来,比如流量较大的服务可以做读写分离。还需要考虑稳定性原则,将成熟改动不大的服务拆分为稳定服务,避免频繁发布,改动多业务迭代快的拆分为变动服务。还可以根据安全隔离进行拆分,区分为对外的跟对内的。还要对重复功能进行沉淀,沉淀为通用服务避免重复造轮子。还有不同语言的可以异构成独立服务。
组织上,根据公司的组织结构来设计,按照康威定律
拆分完如何验证合理性:还是要从业务、技术、组织结构上来评估合理性,业务上能不能满足当前跟未来的发展;技术上性能、安全性、部署维护成本;组织上是不是促进团队协作跟沟通。微服务的拆分跟合并是一个持续演进的过程,需要不断的迭代优化。
kafka为什么支持高吞吐。
分区分段与并行处理。topic 分成多个分区,不同分区在不同服务器上,还对数据进行分段分段之后再加索引,生产者消费者并行处理。
批量读写、批量压缩
直接用系统的 page Cache,读写都基于内存。又使用了零 copy 技术直接将数据 copy 到 nic 缓冲区,减少数据在用户空间跟内核空间复制。
顺序写磁盘技术。减少磁盘寻址时间,当然带来的问题就是不能删数据
使用 kafka 如何避免消息丢失。
生产者使用 ack 机制,0 消息发出就算成功、1broker 的 Leader 副本收到就算成功、-1Leader 跟 follower 都写入成功;
broker 是异步刷盘也有可能失败,但是设置了一个分区几个副本,设置刷盘频率
消费者这边设置提交 offset 的机制,关闭自动提交消费完成之后再提交,支持幂等消费
数据库三范式。原子性、唯一性、冗余性
SQL 优化。创建合适的索引,唯一索引、普通索引、复合索引。SQL 语句优化,不在索引列使用函数,不在 where 语句上使用操作符,不在 where 上进行 null 判断,不在 where 使用 or 来连接条件,模糊查询 %在后面。
怎么排查 Java 程序占用 CPU 过高。
JPS 查看本机线程信息。
top 命令找到占用最高的进程 PID,
在用(top -hp PID)查看进程下的线程 ID 转换为 16 进制线程 ID TID(printf"%x\n" tid),
jstack 打印线程堆栈。jstack PID 命令生成 Java 进程的线程快照,在快照里面通过 TID 找到堆栈(jstack pid | grep tid -A 60)
Jstat 监控JVM内存。如果 gc 过高继续用 jstat -gc pid 3000,如果 fgc 频率高就用 jstack 跟 jmap 分析堆内存使用情况
Jmap 生成内存快照。用 jmap -dump:format=b,file=heapdump.phrof pid 命令去生成 dump 文件然后用专用软件如 jprofiler
常用的设计模式
单例、工厂、适配器、观察者、建造者、策略模式、责任链、代理模式
synchronized
和Lock
的区别synchronized:Java 关键字,jvm 层面实现的隐式锁不需要自己释放,可以加在方法或者代码块,可重入不可中断非公平锁。低竞争模式下性能好,因为使用了 CPU 的悲观锁,并且排它锁第二个线程获取不到锁会一直等待。偏向锁、轻量级锁、重量级锁
Lock:是一个类,需要自己手动释放,可重入可中断可以是公平锁也可以非公平,高并发时候性能好,因为是乐观锁,AQS+CAS 实现的,AQS 就是维护锁状态跟先进先出队列,CAS 是硬件级别的原子操作会尝试更新锁状态。
线程池
FixedThreadPool,固定大小线程池,比如查询数据库,阻塞队列
SingleThreadExecutor,单线程,比如处理文件读写,阻塞队列
CachedThreadPool,动态线程池
ScheduledThreadPool,定时执行的线程池
实际使用中自己通过 ThreadPoolExecutor 创建线程,CPU 密集型任务比如视频解码数据加密,核心线程数跟最大线程都可以是 CPU 线程数+1,线程超过 CPU 核心数增加上下文切换开销,额外一个线程是因为某线程因为页缺失等原因阻塞时可以继续利用 CPU。IO 密集型任务可以配置 CPU 的 2 倍,最大线程可以设置 2~3 倍
thrift
支持二进制跟文本传输协议,支持基本类型、结构体、集合、异常类型、服务类型,底层是 RPC 远程调用,定义好协议格式,主要是数字
char 跟 varchar 区别
char,固定长度适合保存手机号、身份证号等定长数据,
varchar,可变长度,适合存 name、地址信息,多一位存储长度
MySQL 数据库索引
通过 B+树存储,叶子结点存放 key 跟 value,其他节点存放 key,叶子结点有引用指向相邻的叶子节点。数据量增加、插入删除数据时会进行重平衡,
SynchronizedMap
使用分段锁保证性能,一次锁住一个桶默认 16 个桶,jdk8 之后也改用 CAS(Compare And Swap)
并发编程三要素
原子性、有序性、可见性
CyclicBarrier 和 CountDownLatch 的区别
count 是线程等待其他线程都执行完当前线程才继续执行,定时任务中并行计算结果出来之后统一处理,计数器只能用一次,
cyclicBarrier 是所有线程都进入 await 方法后同时执行, 计数器可以 reset,处理复杂场景比如计算错误再来一遍
技术难点
如何让上游无感知迁移流量。在原有 SDK 接口上面增加一个切面吧流量拿到改成调用服务 B;处理蜂窝刷新问题,将门店切成 10 份分散执行,执行中使用线程池并行计算,拿到结果再批量入库。
JVM 内存
堆、方法区是线程共享,虚拟机栈、本地方法栈、程序计数器是线程独有。垃圾回收主要针对堆,堆主要存放 new 出来的对象(方法中对象引用没有被返回或没有在方法体外被使用),新生代(eden、from suvivor、to suvivor)、老年代。方法区之前存在永久代 8 之后被元空间替代,永久代有内存溢出风险、垃圾回收效率低、无法动态调整大小、无法回收常量池中的内存。元空间存储在本地内存不在 jvm,突破内存限制减少 OOM,可以动态调整大小。缺点也可能内存溢出、需要重新考虑内存管理和调优
分享一份大彬精心整理的大厂面试手册,包含计算机基础、Java 基础、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等高频面试题,非常实用,有小伙伴靠着这份手册拿过字节 offer~【领取/点击】
评论