其它面试题


Linux

Java相关命令

列出所有包含 “java” 的进程

ps aux | grep java  

通过进程名搜索

ps aux | grep 进程名
```  

强制终止进程id为PID的程序
``` Bash
kill -9 <PID>
```  

运行时指定 JVM 参数:
``` Bash
java -Xmx1024m -Xms512m -jar MyApp.jar 

常见 JVM 参数:
-Xmx: 最大堆内存(如 -Xmx4g)
-Xms: 初始堆内存
-XX:+UseG1GC: 使用 G1 垃圾回收器
-XX:+HeapDumpOnOutOfMemoryError: OOM 时自动生成堆转储文件

  1. 查看 CPU、内存、磁盘、负载
    查看 CPU / 负载:top、htop
    查看内存:free -h
    查看磁盘:df -h
    查看目录大小:du -sh 目录
    系统负载:uptime

查看端口占用

netstat -tulpn | grep 端口
lsof -i:端口

杀死进程

kill -9 PID

查看日志常用命令

实时看日志:

tail -f xxx.log

看最后 N 行:

tail -n 200 xxx.log

搜索日志:

grep '关键字' xxx.log
grep -C 10 '关键字' xxx.log  # 前后10行

翻页查看:

less xxx.log

文件查找

按文件名查找:

find /path -name "xxx.jar"

按内容查找:

grep -r "内容" /path

进程相关

查看 Java 进程:

运行
ps -ef | grep java

优雅停止:kill PID
强制杀死:kill -9 PID

磁盘满了怎么排查?

df -h 看哪个盘满
du -sh /* 看大目录
重点清理:
日志文件 .log
临时文件 /tmp
大文件无用备份

CPU 高怎么排查?

top 找到高 CPU 进程 PID
top -Hp PID 找到高耗 CPU 线程
将线程 ID 转 16 进制
jstack PID 导出栈,定位代码块

内存溢出 / 泄漏怎么定位?

看内存:free -h、top
导出堆 dump:
bash
运行
jmap -dump:format=b,file=heap.hprof PID
用 MAT/JProfiler 分析泄漏点

软链接、硬链接区别

硬链接:同一个 inode,删原文件不影响
软链接:类似快捷方式,原文件删了失效
创建:
bash
运行
ln 源文件 目标 # 硬
ln -s 源文件 目标 # 软

权限问题(rwx)

r=4,w=2,x=1
755:所有者读写执行,其他读执行
777:所有权限(不推荐生产)
修改:
bash
运行
chmod 755 文件
chown 用户:组 文件

定时任务

bash
运行
crontab -e
示例:每天凌晨 2 点执行
plaintext
0 2 * * * /脚本.sh

网络问题

测试连通性:ping IP
测试端口通不通:telnet IP 端口、nc -zv IP 端口
查看路由:route -n

消息队列

消息队列的话,它主要是一种用于异步通信的中间件,核心就是异步通信和解耦

网络通信相关

TCP与UDP的区别;

TCP 是面向连接的(需三次握手建立连接),UDP 是无连接的(直接发送数据)
TCP 保证数据可靠传输(确认、重传、排序),UDP 不保证(可能丢包、乱序)
​适用场景
TCP 用于文件传输、网页浏览等可靠场景;UDP 用于视频流、在线游戏等实时性要求高的场景。

TCP 的三次握手(建立连接)​
目的:确保双方能正常通信,并同步初始序列号(ISN)。

TCP协议的三次握手,四次挥手

​过程
​第一次握手
客户端发送 (请求连接),进入 SYN_SENT 状态。
​第二次握手
服务器回复 (收到客户端请求),进入 SYN_RCVD 状态。
​第三次握手
客户端发送 连接建立

TCP 的四次挥手(断开连接)​
目的:确保双方数据完全传输完毕后再释放连接。

​过程
​第一次挥手(FIN)​
主动方(如客户端)发送(请求断开)
​第二次挥手(ACK)​
被动方(如服务器)回复 (收到断开请求)
​第三次挥手(FIN)​
被动方发送 (确认自己数据已发送完毕)
​第四次挥手(ACK)​
主动方回复 (确认被动方断开),被动方收到后直接关闭。

网络通信的三要素

IP,端口,传输协议


Quartz

Quartz的 ​Cron 表达式

​Cron 表达式用于定义复杂的定时任务调度规则
字段顺序:秒(0-59) 分(0-59) 时(0-23) 日(1-31) 月(1-12) 周(1-7) [年(可选)]
特殊符号:

*       : 任意值(如秒=*)
?       : 不指定值(仅用于日和周字段,避免冲突)
-       : 范围(如日=1-5)
,       : 列表(如周=1,3,5)
/       : 步长(如秒=0/15 表示每15秒:0,15,30,45)
L       : 最后(如日=L 表示月末)
W       : 最近工作日(如日=15W 表示离15号最近的工作日)
#       : 第几个(如周=6#3 表示每月第三个星期五)

集群与分布式

集群(Cluster)​
​概念:一组通过高速网络互联的物理或虚拟服务器,协同工作以提升系统的性能、可靠性或扩展性。
​目标:通过资源聚合(如计算、存储、网络)实现高可用性或高性能。
​特点:
节点通常位于同一数据中心或相近网络环境。
节点间共享负载(如负载均衡集群)或共同完成任务(如高性能计算集群)。

​分布式系统(Distributed System)​
​概念:由多个独立计算机节点通过网络连接组成的系统,节点协同完成统一任务,对外表现为单一系统。
​目标:通过跨节点协作实现资源共享、容错性和地理分布支持。
​特点:
节点可分布在不同地理位置,甚至异构环境(不同硬件、操作系统)。
强调数据一致性(如分布式数据库)或任务协调(如区块链)。

容器和虚拟机的区别

容器和虚拟机都是虚拟化技术
容器是“轻量级进程隔离”,适合敏捷开发和云原生;虚拟机是“完整的系统虚拟化”,适合强隔离和异构环境

Docker和Kubernetes(k8s)

Docker 是容器化技术,负责打包和运行单个容器
​Kubernetes 是容器编排工具,负责管理多个容器(尤其是跨主机集群)的生命周期,提供高可用性、弹性伸缩等能力

你们这个项目如何部署的

我们这个项目就是所里边的人用,更新的时候就说一下,然后就是直接打成jar包传到服务器
启动的时候用的是nohup命令
nohup java -jar jar包

服务器用的是

nginx

设计模式

单例模式的实现方式?懒汉式和饿汉式区别?

饿汉式:类加载时创建实例,线程安全,缺点:启动慢、浪费内存;
懒汉式:使用时创建,线程不安全(加 synchronized / 双重检查锁解决);
推荐:双重校验锁的懒汉式实现、枚举(防止反射破坏)。
场景:工具类、配置类、线程池、数据库连接池
开发里常用双重校验锁的懒汉式实现,
项目里的库存统计工具类、全局配置读取类都用了,保证全项目一个实例,避免重复创建浪费资源,还兼顾了懒加载和线程安全。
双重校验锁的懒汉式实现:核心是把构造器私有,通过全局静态方法获取唯一实例,避免重复创建对象浪费资源,同时保证多线程场景下调用不出问题

工厂模式

简单工厂:一个工厂造一类产品。
工厂方法:每个产品对应一个工厂。
抽象工厂:造一 “家族” 的产品。
好处:解耦,调用方不用关心对象怎么创建,以后换实现不用改代码。
核心是工厂方法模式:

  1. 定义统一的数据源解析接口:抽离所有数据源解析的公共方法,比如(数据接入)、(数据解析)、(解析后数据校验)
  2. 为每个数据源写专属的解析实现类:比如wos解析类、IEEE 解析类、
  3. 封装简单工厂做解析对象的统一创建:写一个数据源解析工厂类,里面根据传入的「数据源类型标识」(比如配置里的 WOS、IEEE、ZIP),动态创建对应解析实现类的对象
    设计核心思路:是用接口定标准、实现类做差异化、工厂做对象创建,核心就是把「对象创建」和「业务使用」解耦,适配多数据源的扩展需求。

代理模式

核心是对方法做前置 / 后置增强,Spring AOP 底层就是这个。

比如后台管理系统的操作日志,
第一步:自定义日志注解,标记需要记录日志的方法
第二步:编写切面类,定义日志的核心处理逻辑
方法执行前:获取操作用户,记录操作开始时间
方法执行后:获取方法执行结果、返回值,;
异常处理:记录异常信息,
第三步:日志持久化与异步优化
把封装好的日志实体类通过Spring 的 @Async 注解交给异步线程池处理,异步将日志写入MySQL 日志表

第四步:全局配置,实现日志的统一管控
在 Nacos 里配置日志记录的开关和日志级别,比如测试环境关闭部分高频操作的日志,生产环境开启全量日志;同时在切面里做了日志过滤,比如忽略一些测试类方法、空数据批次的操作,避免无效日志产生,让日志记录更精准

核心业务代码里完全没有日志相关代码,保证了核心逻辑的纯净性,后期排查问题时,能通过日志表快速追溯每一次数据处理的全链路信息

Java常见数据结构及特点

​数组(Array)​

数组是通过连续的内存空间存储元素,每个元素位置由索引直接定位

  • 特点:连续内存、索引直接访问速度快、大小固定。
  • 适用:频繁随机访问、内存敏感场景。
  • 扩容成本高:需创建新数组并复制旧数据
    数组是内存效率最高、访问最快的结构,但灵活性差;适合静态数据或已知大小的场景,动态场景优先用ArrayList

队列

队列是先进先出​的结构,核心操作:​入列​、出列​、判空。

  • 类似于单向管道,先进去的先出来
  • ​顺序性:元素按加入顺序排列,先进入的先被移除。
  • ​两端操作:仅在队首(Head)出队,队尾(Tail)入队。
  • ​状态检查:需支持判断队列是否为空。
    ​核心原则:队列的核心是顺序控制,选择时需平衡操作频率与性能需求。

链表

链表是通过节点(Node)​链接数据,每个节点包含值域和指针域​(指向下一个节点)

  • ​动态大小:无需预分配内存,按需扩展。
  • ​插入/删除快:只需调整指针(O(1)时间,头尾最优)。
  • ​随机访问慢:需从头遍历(O(n)时间)。
  • ​内存碎片:节点分散存储,缓存命中率低。
    应用场景
    ​动态数据集:频繁增删但少查询的场景(如LRU缓存淘汰机制)。
    ​内存敏感场景:节点可动态分配,适合大规模数据存储。
    ​队列/栈实现:链表可实现高效的头尾操作(如Java的LinkedList底层是双向链表)。
  • 总结
    ​单链表:内存占用小,但尾插和删除需遍历。
    ​双向链表:功能更强大,但指针维护稍复杂。
    ​适用原则:
    ​高频头尾操作 → 双向链表。
    ​仅需单向遍历 → 单链表。
    ​线程安全 → 用ConcurrentLinkedDeque


文章作者: zrh
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 zrh !
  目录