news 2026/8/11 14:37:48

java面试常见的问题以及解决方法

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
java面试常见的问题以及解决方法

一. 网络抓包问题:

常用的网络抓包工具:

1. tcpdump:最常用的命令行抓包工具,功能强大,可过滤各种协议。Linux、macOS

2. Wireshark: 最强大、最常用的 GUI 抓包工具,支持协议解析、图形化分析等。 Windows、Linux。

3. Fiddler: 专注于 HTTP/HTTPS 抓包,可解密 SSL,非常适合 Web 接口调试。Windows。

系统架构

  • 前端页面部署在浏览器或 nginx 上

  • 后端服务地址为:192.168.1.100:8080

  • 前端请求一个接口:http://192.168.1.100:8080/api/user/info

问题描述

  • 前端控制台显示:请求已经发送(200 或 pending)

  • 后端接口没有打日志、调试器没有命中、服务无响应

tcptump命令进行抓包:

sudo tcpdump -i any port 8080 -n -X
-i any:监听所有网络接口

port 8080:只看目标端口 8080

-n:不进行 DNS 反查

-X:显示数据内容(可看 URL)

tcpdump -i eth0 port 8080 # 只抓 8080 端口
tcpdump -i eth0 tcp # 只抓 TCP
tcpdump -i eth0 # 抓所有

常用tcpdump命令选项

  • -i [interface]:指定监听的网络接口。

  • host [IP]:过滤与指定 IP 地址相关的流量。

  • port [number]:过滤指定端口的流量。

  • -w [file]:将捕获的数据包写入文件。

  • -c [number]:捕获指定数量的数据包后停止。

  • -nn:不将地址和端口转换为名称,显示原始数字

sudo tcpdump -i eth0 host 192.168.1.100 and port 80 -w /tmp/capture.pcap
此命令的含义:

-i eth0:指定监听的网络接口为 eth0。

host 192.168.1.100:过滤与该 IP 地址相关的流量。

port 80:过滤 HTTP 通信。

-w /tmp/capture.pcap:将捕获的数据包写入文件。

tcpdump -s 0 -i eth0 port 22 -nn -tttt > output.txt

-s 0:抓取数据包的完整内容(头 + body),适合调试 HTTP/SSH 等有 payload 的协议;

-i eth0:监听 eth0 接口;

port 22:过滤 SSH 通信;

-nn:不解析主机名和端口名;

-tttt:显示精确时间戳;

> output.txt:将抓包结果保存到文本文件中。

二. 线上死锁问题排查(数据库死锁,代码死锁)

什么是死锁?

死锁表现,程序不往下走了。

并发场景下,多个线程在竞争相同的资源。线程1要获取到资源需要持有A,B两把锁,线程2要获取到资源需要持有B,A两把锁。线程1在持有A锁尝试去获取B锁,线程2在持有B锁尝试去获取A锁。

两个线程都持有对方需要的资源,等待对方释放资源的过程,称为死锁。

解决方法:1. 一个线程避免持有多把锁 2. 确保所有的线程按照相同的顺序获取锁,避免等待。

3. 使用超时机制:线程在获取锁的过程中,如果超时则放弃获取锁,避免长期等待出现死锁。

死锁定位的方法:

1. 通过jps命令找到所有的进程

2. 通过top -H p pid n 1 : 生成对应进行下面所有线程cpu和内存使用情况的快照信息

3. jstack -l pid > ./file.txt生成对应的线程快照文件

4. 在文件中搜索deadlock字段信息。找到全路径类名,代码定位分析。

三. 线上OOM问题排查

现象:用户在下载报表的过程中,每隔几个星期出现下载报表失败现象。

排查:取下gc日志和后端日志,查看日志发现在下载报表的过程中,jvm在不断的进行full gc,老年代内存不见较少反而不断地增加,最终导致内存不足出现OOM现象。

根据以往的经验,可能有两点原因导致。

1. JVM 初始化堆内存配置过小; 2. 存在大对象未及时释放,造成内存泄漏。

第一:先排查第一种情况:java -XX:+PrintCommandLineFlags -version命令,发现初始化堆内存:1g,最大堆内存是4g。内存配置合理,暂时排除配置问题。

第二: 对象泄漏分析
线上已预配置-XX:+HeapDumpOnOutOfMemoryError-XX:HeapDumpPath,在 OOM 发生时自动生成了.hprof堆转储文件。使用 VisualVM 工具打开该文件,发现Workbook对象占用堆内存超过 50%,存在明显内存泄漏。

分析过程:初步判断可能是这个大的对象用完以后没有被及时的释放导致的,通过全路径类型定位到代码进行分析。发现workbook对象生成报表以后,没有及时调用close()方法关闭资源导致。

解决方法:修改代码逻辑workbook对象生成报表以后,及时调用close()方法关闭资源。然后,从新打包替换生产的jar包,从新启动程序。

验证:

1. 通过jstat -gc pid 500(ms): 查看垃圾回收趋于正常。

2. 报表下载一周没有出现失败的情况

堆转储文件生成的方式两种:

1. 通过事先参数配置:-XX:+HeapDumpOnOutOfMemoryError,XX:HeapDumpPath=/opt/dumps

非核心业务模块

2. 通过命令生成:jmap -dump pid生成 (jps命令查看保证进程还在,如果进程不在不能使用)

核心业务模块(非高负载情况下)

面试官追问线上环境不能使用直接生成:

线上环境并不是绝对不能使用,但要谨慎使用。

优点:OOM时候可以自动生成堆转储文件,方便内存溢出问题的排查。

缺点:生成堆转储文件可能占用大量的内存,导致程序卡顿或者雪崩。

因此,非核心模块开启自动生成。(并且设置磁盘的告警和定期的清理)

核心业务模块不开启,通过监控工具进行监控(如 Prometheus + Grafana)提前预警。使用jmap -dump命令手动生成。

四. JVM的调优的经验

常见的调优参数:-xms:初始化堆内存大小 -xmx: 最大堆内存大小 -xss:每个线程的栈堆大小。

JVM参数可以在哪里设定:

JVM调优参数有哪些?

1. 堆空间的大小

为了防止垃圾收集器在初始化大小和最大大小之间收缩堆空间,造成时间的浪费,一般把初始化和最大堆大小设置成一样的。

如何设置堆空间:1. 初始化堆大小:物理内存的1/64 最大堆大小:物理内存的1/4

2. 堆内存设置过小,会导致年轻代和老年代不断地进行垃圾回收,导致stw

3. 堆内存设置过大,在进行FULL GC的时候,会扫描整个堆空间,造成时间浪 费。

stop the world: JVM在进行某些垃圾回收的时候会暂时停止应用线程的工作,只让垃圾回收线程进行工作,保证数据的安全性。

详细步骤:1)默认情况下,初始化堆内存为物理内存的1/64,最大堆内存为物理内存的1/4。

在进行调优的时候,如果我们的服务对内存要求不需要特别精确,可以遵循堆内存尽可能大的原则,将初始化堆内存和最大堆内存设置成一样,可以避免堆伸缩。

2)如果我们服务对内存的要求特别的精确,我们可以给堆内存设置一个初始值,然后启动服务,通过Visual VM工具进行连接观察的。

主要观察一下参数:

1. 堆内存的使用情况: 服务在运行期间,程序使用的堆内存峰值不能超过预先设置的堆内存的最大值。如果超过需要增加堆内存参数值。

2. 垃圾回收情况: 如果在服务的运行期间,频繁的进行垃圾回收,特别是FULL GC操作,说明设置的堆内存空间过小,适当的提高堆内存空间(20%-30%)

3. 线程和CPU的使用:定位死锁和CPU过高问题

将调节好的新的参数,应用到服务上面,从新启动服务然后进行观察。多次调整保证最合适的值。

保证:1. 服务在运行期间使用最大内存不能高于设定的最大堆内存 2. 垃圾回收不频繁,不出现OOM现象。

2. 栈空间的大小

-xss:栈空间不能设置过小也不能过大。过小会导致JVM频繁的进行GC操作,会导致STW,甚至导致stackoverflowerror出现。过大JVM在进行FULL GC的时候会整堆进行扫描,浪费时间。

可以通过以下方法考虑:

1. 高并发场景下:线程会比较多,这个时候将栈空间设置的小一些,防止系统内存不足,线程无法创建。

2. 业务代码比较负载:业务代码比较复杂方法存在大量的递归调用,这个时候栈空间设置的大一些。防止出现栈内存溢出的风险。

3. 年轻代和老年代如何调优

年轻代进行调优:

第一种情况:Minor GC频繁,对象过早的进入老年代。

Minor GC大致频率?默认情况(老年代:年轻代=2:1)
常见应用中可能是几秒 ~ 几十秒一次,高频操作中甚至可能每秒一次或更多

Minor GC频繁(一秒多次):说明enden区的空间不足,增加-xmn(年轻代参数设置)大小,或者增大年轻代的占 比。

对象过早进入老年代:说明幸存者区空间不足,将 Eden:S0:S1 =6:1:1(默认8:1:1)

老年代调优: FULLGC频繁,说明老年代内存不足。

解决方法:增加老年代的占比(3:1),增加堆内存,调整-xms,-xmx大小。

4. 垃圾收集器的选择

Serial: 如果应用服务是在单核cpu的情况,且对并发性要求不是很高的情况下,采用该垃圾收集 器。

parllal: 如果应用服务是在多核cpu上的,且服务对并发性要求比极高,采用该收集器。

CMS, Shenandoah(java 12+): 当应用程序对响应时间比较敏感的时候,采用该垃圾收集器。

G1,ZGC(java 11): 如果涉及到大堆回收,应用程序对响应时间要求也比较高的情况下,可以采用者两种垃圾收集器。

G1和ZGC的区别:G1适应与低延迟(可配置的),中大型的堆内存回收(几GB或者几百GB)。支持并发标记回收。(会出现STW)

ZGC:支持超低级别的延迟(<10ms),超大类型的堆回收(TB级别),支持并发标记回收,

通过找色指针和读屏障实现对象的转移。(不会出现STW)。

STW 是 Stop The World 的缩写,意思是 “暂停世界”。

在 JVM 中,它表示在某些操作(比如垃圾回收、类加载、栈扫描等)时,JVM 会暂停所有正在运行的应用线程,只让 GC 线程或其他系统线程运行,以保证数据一致性。

总结: 四个方面进行调节,每个方面细讲。

五. CPU和内存占用率过高

1.cpu过高分析:

什么情况下过高:1. 无限循环或者死循环 2. 高并发场景 3. 锁竞争激烈 4. 不断地发生GC操作,特别是FULL GC。

cpu过高如何进行定位:1)通过top命令找到cpu占用率比较高的进程 2)top -H p pid n1 找到该进程下线cpu占用率比较高的线程,并将线程id号转化成16进制 3)通过jstack -l pid > ./file.txt生成线程快照文件 (生成该进程下面所有线程的调用栈信息)4)在file.txt 中搜索转换后的16 进制线程 id,即可找到哪个线程导致cpu占有率过高 5)通过全路径类名定位到代码里面去排查

2.内存过高分析

什么情况下内存过高:1. 对内存泄漏 2. 堆外内存泄漏 3. 线程数量过多,导致占内存使用过大 4. 大对象和数组的频繁创建 5. 缓存使用不当

排查:1)top命令找到占用内存高的进程 2)jmap -dump命令生成堆转储文件 3)通过visual vm工具打开进行分析,找到内存占用比较大的对象

4)定位到代码进行分析

六. 如何进行分库和分表

一. 为啥需要分表?

1. 单表的数据量太多,做了很多优化以后仍然无法提升效率。

2. 索引一般是B+树的结构,树的层级变高,查询的速率会变慢。

二. 哪些分库分表的工具?

1. sharding-jdbc: 优点: 不需要部署,运维成本低。 缺点:耦合度高,各个模块都依赖于 sharding-jdbc,不利于扩展。

2. mycat: 优点:耦合度低,系统升级容易。

三. 分表的策略:

1. 范围分片:表1:0-1000000 表2: 1000001 - 2000000

优点:操作简单 缺点:热点数据集中,易倾斜。

2. hash分表:(取模运算)user_id % 4结果落在4个表/库中

优点:数据分布均匀,不会出现数据倾斜。 缺点:不能进行范围查询,扩容成本高。

3. 按日期(时间分片,按照月年进行划分):夸表查询复杂

四. 分表以后出现的问题:

1. ID唯一性问题?

1. 采用雪花算法 (64位唯一id) 2. 使用数据库的分段式(每张表的自增id从不同区间开始)

2. 事务的一致性问题?

最终一致性解决方案(TCC, 本地消息表)

3. 查询问题

如何实现count(*)、聚合查询、分页、排序

1. 如果查询不频繁,直接在业务代码里面查询每张表,然后在内存中聚合分页。

2. 如何需求复杂,查询频繁,采用ShardingSphere这样的分页工具进行分片,路由,分页和聚合。

如何实现join查询:

1. 使用相同分片规则的(如user_id),实现同分片 JOIN。

2. 从每个分片表查询出数据,在应用层做关联。

3. 设计冗余字段,业务上避免 JOIN;(order表中冗余如用户名、手机号等)

直接通过order表查询。

4. 数据迁移和扩容难

初期分表hash数量不足,相对容易,后期需要增加库表,代价比较大(需要从新进行hash分表)hash%16------->hash%64

五. 为啥要分库?(单库超过100GB需要进行分库)

1. 数据量比较大,磁盘的容量被撑爆。

2. 数据库的连接数有限,高并发的场景下,会出现 too many connections报错。

六. 分库的策略:

1. 范围分表

user_id<1亿存A库 user_id>1亿存B库

在对1亿数据进行划分:采用hash算法,hash%16

2. hash分表

3. 时间分表

七. 分库出现的问题:和分表类似,最主要存在的跨数据库事务的问题。

八. 分库实现查询问题

回答:分库无法直接跨库执行sql,可以采用应用层路由+聚合查询。先查询每个分库,再在业务层合并结果。或者使用中间件shardingpheres自动实现路由,执行,聚合,排序

shardingpheres分片的规则:1.奇偶性 2. hash算法

参考链接: mysql面试之分库分表总结-EW帮帮网

七. 微服务的优缺点和划分原则

和传统的单体架构相比:

传统的单体架构:1)启动时间长,不利于协同开发,一个人开发完成以后不能单独上线,要等所有人都开发完成以后才能上线。

2)传统的单体架构所有的模块都集中在一起,高并发场景下,不利于压测扩容,整体扩容会导致资源的浪费

3)传统的单体架构业务代码会越来越复杂,不利于代码的维护。老员工离职以后,新员工很难维护代码。

微服务架构:1)项目启动时间段,有利于协同开发,每个人只需要负责开发自己的模块即可。

2)高并发场景下面利用压测,对并发场景高的模块进行扩容,并发场景的低的不进行扩容,有利于很好的利用资源。

3)利用代码的维护,每个人只需要维护自己负责的模块。代码的耦合性比较低。

缺点:

1)微服务可能要部署十几到几十个模块,给运维人员带来了很大的压力。

2) 微服务涉及到多个模块之间的调用,涉及到数据一致性问题。

3)微服务涉及到跨服务,跨服务器之间的通信,对编程人员的能力有一定的要求。

八. 前端面试知识

九. 分布式事务

1. 两阶段提交

概念: 用来保证分布式事务一致性的协议,用来保证在多个参与者参与的节点中,事务要么全部提交,要么全部回滚。

两阶段:准备阶段:协调者向所有参与者询问是否可以执行事务操作,参与者本地执行事务,但是不提交事务。并将事务执行结果yes/no返回给协调者。

提交阶段:当所有参与者均返回yes给协调者,协调者通知所有参与者提交事务。有一个参与者返回no给协调者,则协调者通知所有参与者进行回滚。

优点:1 ) 保证事务的原子性和强一致性。

缺点:1) 同步阻塞问题:所有事务的参与者在等待其它参与者执行的时候,都处于等待状态。 2)单点故障问题:当协调者出现故障的时候,所有的参与者都处于等待状态,无法正常工作。

适应场景:适用于对一致性要求极高、参与方较少的系统。

2. 补偿事务(TCC)

try阶段:尝试执行业务,检查并预留资源空间,并不提交。

confirm阶段:所有的try阶段都成功以后,正式执行对应的业务(并提交事务)。

(confirm阶段做了幂等性的处理,执行多次的结果保持一致)

cancel阶段:任何一个try没有成功,就进行回滚。(cancel是为try阶段提供用来回滚的)

假设一个电商下单操作,涉及扣库存扣余额两个服务:

✅ 1. Try 阶段(预处理)

  • 商品服务冻结库存

  • 账户服务冻结余额

  • 仅做预留,不做实际扣减

✅ 2. Confirm 阶段(正式提交)

  • 商品服务真正扣减库存

  • 账户服务真正扣减余额

  • 幂等性处理,防止重复提交

✅ 3. Cancel 阶段(补偿回滚)

  • 商品服务解冻库存

  • 账户服务解冻余额

  • 恢复 Try 阶段的预处理

案例:

// Try 阶段:冻结余额
public boolean tryFreeze(String userId, BigDecimal amount) {
// 检查余额是否充足
// 冻结余额 = amount,写入冻结表
// 返回成功或失败
}

// Confirm 阶段:正式扣款
public boolean confirm(String userId, BigDecimal amount) {
// 从冻结表扣减余额
// 删除冻结记录
// 幂等处理
}

// Cancel 阶段:解冻余额
public boolean cancel(String userId, BigDecimal amount) {
// 将冻结的余额退回
// 删除冻结记录
// 幂等处理
}
本地消息表:

总的来说有三个阶段组成,第一事务发起阶段,第二消息投递,第三消息消费阶段。

第一阶段:当应用执行本地的业务操作时候(如减少库存),在本地的同一个数据库事务中,要把分布式消息(生成订单)插入到本地消息表。(本地业务操作和消息插入到本地消息表是原子操作)

CREATE TABLE local_message (
id BIGINT PRIMARY KEY, -- 消息唯一ID(如雪花算法)
biz_id VARCHAR(64), -- 业务唯一标识(如订单ID)
status TINYINT, -- 状态:0(待发送)、1(已发送)、2(已完成)
payload TEXT, -- 消息内容(JSON格式的业务数据)
retry_count INT DEFAULT 0, -- 重试次数
next_retry_time DATETIME, -- 下次重试时间
created_time DATETIME -- 创建时间
);

第二阶段消息的投递阶段:通过独立的消息发送服务,或者定时任务定时轮询消息表里面状态是未发送的任务,将消息投递到kafka,MQ等消息队列里面。

如果消息投递成功,修改本地消息表里面的消息的状态为已发送。如果投递失败则进行重试。

第三阶段:下游的消费者监听MQ,当收到消息以后。

1. 先进性幂等性的效验:通过订单id查询订单表里面有没有该条记录,如果没有。

2. 执行本地事务,生成订单。

3. 响应MQ结果:成功,向MQ发送ACK,MQ删除该记录,或者标记为已完成。

失败,日志记录并触发告警,依赖ACK的重试机制。

4. 对账补偿
  • 定时对账任务
    检查长时间处于“已发送”状态的消息(如超过1小时未完成),主动查询下游业务状态:

    • 若下游业务已成功,更新消息状态为“已完成”。

    • 若下游业务失败,触发告警并人工干预或自动回滚(如调用冲正接口)。

设计的关键要点:

1. 消息可靠性保障
  • 本地事务与消息的原子性
    使用数据库事务确保业务操作和消息写入同时提交或回滚。

    java

    复制

    下载

    @Transactional public void createOrder(Order order, Message message) { orderDao.insert(order); // 业务操作 messageDao.insert(message); // 写入消息表 }
  • 消息投递重试机制
    采用指数退避策略(如1s、3s、10s)逐步拉大重试间隔,避免雪崩。

2. 消费端幂等性
  • 唯一业务标识
    使用biz_id(如订单ID)作为去重依据,确保同一业务仅处理一次。

    SELECT COUNT(*) FROM order WHERE order_id = #{biz_id};
  • 数据库唯一约束
    在业务表设计时,对biz_id添加唯一索引,防止重复插入。

3. 最终一致性延迟
  • 异步消息的延迟
    消息从产生到处理完成可能存在秒级甚至分钟级延迟,需业务容忍短暂不一致(如“支付成功”后短暂显示“待发货”)。

适应的场景:

  1. 跨服务事务:如电商的“扣库存→生成订单→通知物流”。

  2. 非强一致性需求:允许短暂不一致,但要求最终一致(如账户余额变动)。

  3. 高可靠系统:对事务丢失容忍度低(如金融系统的转账记录)

示例代码:

// 1. 业务服务(库存服务)
public class InventoryService {
@Transactional
public void deductStock(String productId, int count) {
// 扣减库存
inventoryDao.deduct(productId, count);
// 写入本地消息表
Message message = new Message();
message.setBizId(UUID.randomUUID().toString());
message.setPayload(buildOrderMessage(productId, count));
messageDao.insert(message);
}
}

// 2. 消息发送服务
@Scheduled(fixedDelay = 5000)
public void sendMessages() {
List<Message> messages = messageDao.selectPendingMessages();
for (Message msg : messages) {
try {
mqProducer.send(msg.getPayload());
messageDao.markAsSent(msg.getId());
} catch (Exception e) {
messageDao.updateRetryInfo(msg.getId());
}
}
}

// 3. 订单服务(消费者)
@RabbitListener(queues = "order.queue")
public void handleOrderMessage(String payload) {
OrderMessage orderMsg = parsePayload(payload);
if (orderDao.exists(orderMsg.getBizId())) {
return; // 幂等性检查
}
orderDao.createOrder(orderMsg);
}

十. 分布式锁

1. 通过redis实现:

两步加锁阶段:set key value nx ex

nx:如果该key不存在,创建该key。

ex: 防止锁长时间不释放

value:用来防止锁误删的,锁只能通过锁的创建者释放。可以使用uuid,雪花算法生成。

释放锁阶段: 通过lua脚本进行释放

缺点:1.单点故障:Redis主从切换可能导致锁失效。 2. 业务没有执行完,锁被释放了

2. 通过redission进行实现

看门狗机制

3. 通过乐观锁实现

  • 实现原理

    • 使用版本号或时间戳字段,更新时校验版本号是否变化。

    • 例如:UPDATE resource SET version = new_version WHERE id = 1 AND version = old_version;

  • 优点:轻量级,避免长期锁竞争。

  • 缺点:需业务逻辑配合,高并发时重试成本高。

  • 适用场景:读多写少、冲突较少的场景。

4. 通过redlock实现

解决单点故障问题

5. 通过zk实现

十一. 数据一致性判断,一般从以下几个方面?

1. 数据库事务 通过 Spring 的 @Transactional 保证一组操作的原子性。
2. 并发控制 通过数据库的悲观锁(select for update) 或 乐观锁(version版本号) 防止并发修改数据。
3. 缓存场景: 一般采用先更新数据库再删除缓存或延迟双删策略。
4. 分布式环境下:分布式环境下使用分布式锁(Redis、Redisson) 来避免多服务并发修改同一资源。
5. 微服务架构中: 通过消息队列保证最终一致性,例如本地消息表、可靠消息机制。
4. 分布式事务框架:比如 Seata 或 TCC 模式 来保证一致性


十二 . 大文件10g以上文件解析的问题

10g文件进行解析读取,如果解析过程中出现异常了,是全部解析流程进行回滚,
下次重新解析。还是记录当前的解析的操作点,下次从该操作点接着解析?

两种方式:
第一种:
全部回滚,下次重新进行解析。不适合大文件。
第二种:记录解析位置,并做幂等性处理。
解析文件

记录当前解析位置

异常

从断点继续解析
记录:
当前文件偏移量
已处理行号
已写入数据
三. 实际工程方案
1 分段解析 2 记录解析进度 3 幂等设计(非常加分) (数据库的唯一索引)

十三. 大的文件解析过程

第一种直接本地磁盘读取文件: BufferedReader br = new BufferedReader(new FileReader("bigfile.txt"))
1. 边读取,边消费。(可以采用NIO模型提高效率) 也可以一个线程读,多个线程消费来提高效率。
2. 事务补偿机制(失败的任务会重新的执行)
3. 记录偏移量,和这次读取的行数,任务失败后,下次读取从失败的地方读取,
提高解析效率。
4. 数据库层面设置幂等性机制,防止数据重复。(设置唯一主键)
第二种通过接口从网络中读取: InputStream is = conn.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is))

1️. 核心问题
文件在远程 → 通过网络获取 → 流式读取。
网络可能慢、不稳定 → 容易超时。
文件很大(几十 GB) → 不可能一次性加载到内存。
同时解析和落地,需要保证效率和稳定性。
(1) 网络流式读取
不要先下载整个文件再解析。
使用 HTTP/FTP/S3 SDK 等的 InputStream,直接边读边解析:
URL url = new URL("http://remote-server/largefile.txt");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);

try (InputStream is = conn.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is))) {
String line;
while ((line = br.readLine()) != null) {
processLine(line); // 解析并落地
}
}
(2) 边读边异步处理
读取线程 → 阻塞队列 → 异步线程池处理。
异步线程池可以调用远程接口解析数据或者做本地落地。
BlockingQueue<String> queue = new LinkedBlockingQueue<>(1000);

Thread reader = new Thread(() -> {
try (BufferedReader br = new BufferedReader(new InputStreamReader(is))) {
String line;
while ((line = br.readLine()) != null) {
queue.put(line);
}
queue.put("EOF");
} catch (Exception e) {
e.printStackTrace();
}
});

ExecutorService processorPool = Executors.newFixedThreadPool(10);
Thread processor = new Thread(() -> {
try {
String line;
while (!(line = queue.take()).equals("EOF")) {
processorPool.submit(() -> {
try {
String result = callRemoteApi(line, 5000); // 超时5秒
writeToLocal(result);
} catch (Exception e) {
writeToFailFile(line);
}
});
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});

3) 批量读取 + 批量调用
如果接口支持,不要每行都调用一次,按 N 行组成一个批次:
List<String> batch = new ArrayList<>();
queue.drainTo(batch, 100); // 每100条组成一个批次
callRemoteApi(batch);
优点:减少网络请求次数,提高吞吐量。

4) 超时和重试策略
网络读取和接口调用都可能超时:
HTTP/FTP 流读取设置 connectTimeout + readTimeout
调用远程接口时也设置超时
失败的数据可以落地到本地文件或者消息队列,后续再重试,不影响整个文件流处理。

十四. 什么是字节流和字符流?

字节流概念:以字节(8位)为单位进行读写,适合处理所有类型的数据(文本、图片、音频、视频等)。
字节流: inputstream,outputstream
字符流(Character Stream)
概念:以字符(16位 Unicode) 为单位进行读写,专门处理文本数据,自动处理字符编码。
顶层抽象类:
Reader(输入字符流),Writer(输出字符流)
BufferedReader / BufferedWriter: 带缓冲区,可按行读写
文本读取在网络上数据传输是不是都是字节流?
1️.网络传输的本质
TCP/HTTP/Socket 等协议都是基于 字节传输 的。
无论你发送文本、图片、音频、视频,网络最终看到的都是 一连串的字节。
网络只负责把这些字节从一台机器传到另一台机器,并保证顺序、完整性(TCP)或不保证(UDP)。
2️.为什么我们还要用字符流?
虽然网络传输的是字节,但如果传的是 文本数据(如 HTTP 请求体、JSON、XML、HTML 等),
就需要 把字节按编码转换成字符 才能方便处理。
Java 提供了 InputStreamReader / OutputStreamWriter 来做 “字节 ↔ 字符” 的转换:
InputStream is = socket.getInputStream(); // 字节流
BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8)); // 转字符流按行读
本质上:
网络底层都是字节流
字符流只是对字节流的包装,为了方便文本处理和编码转换、按行处理大文件

十五. 雪花算法和uuid的区别?

雪花算法:

64bit结构:
1bit 符号位
41bit 时间戳
10bit 机器ID
12bit 序列号
4096 × 1000 = 409.6万 ID / 秒

全局唯一:
时间戳 + 机器ID(区分不同的节点) + 序列号
只要:
机器ID不同
时间不回拨
ID 就不会重复。

雪花算法:
生成 64 bit Long 类型ID。
趋势递增: 按时间递增
支持分布式:不同机器生成不同ID
生成速度快(高性能):本地生成无需网络

UUID:

UUID 是一种 全局唯一标识符,标准长度 128 bit。
特点:唯一性,无序,36字符
缺点:
字符串很长 不适合作为数据库主键 索引效率低 不具备时间有序性

UUID vs 雪花算法对比
| 对比项 | UUID | 雪花算法 |
| ----- | ------ | ----- |
| 长度 | 128bit | 64bit |
| 类型 | 字符串 | Long |
| 是否有序 | 无序 | 趋势递增 |
| 数据库索引 | 差 | 好 |
| 生成方式 | 随机 | 基于时间 |
| 适合做主键 | 不推荐 | 推荐 |
| 可读性 | 差 | 较好 |

十六. 对象的生命周期?

1 创建对象
2 分配堆内存
3 调用构造方法
4 程序使用对象
5 对象没有引用
6 GC判断对象不可达
7 垃圾回收
8 内存释放

年轻代 GC(通常叫 Minor GC 或 Young GC)并不是“每隔几秒固定执行一次”,
而是 在特定条件触发时执行。最常见的触发条件是 年轻代(尤其是 Eden 区)空间不够。
内存驱动而不是时间驱动。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/14 15:39:31

ROPE编码

参考&#xff1a;https://www.zhihu.com/tardis/bd/art/647109286def apply_rotary_pos_emb(x: torch.Tensor, pos: torch.Tensor) -> torch.Tensor:"""apply rotary position embeddingx: [b, num_heads, num_tokens, head_dim]pos: [b, num_tokens, 2]retu…

作者头像 李华
网站建设 2026/7/14 15:39:29

Jazzer进阶:自定义sanitizers开发指南与最佳实践

Jazzer进阶&#xff1a;自定义sanitizers开发指南与最佳实践 【免费下载链接】jazzer 项目地址: https://gitcode.com/gh_mirrors/ja/jazzer Jazzer是一款强大的Java模糊测试工具&#xff0c;通过自定义sanitizers可以显著提升漏洞检测能力。本文将深入探讨如何开发自定…

作者头像 李华
网站建设 2026/7/14 15:39:30

基于鱼群算法的单目标工艺参数最优化-响应面(RSM)附Matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;擅长数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。&#x1f34e; 往期回顾关注个人主页&#xff1a;Matlab科研工作室&#x1f34a;个人信条&#xff1a;格物致知,完整Matlab代码及仿真咨询…

作者头像 李华
网站建设 2026/7/14 15:39:45

SpongeAPI完全指南:从零开始构建你的Minecraft插件帝国

SpongeAPI完全指南&#xff1a;从零开始构建你的Minecraft插件帝国 【免费下载链接】SpongeAPI A Minecraft plugin API 项目地址: https://gitcode.com/gh_mirrors/sp/SpongeAPI SpongeAPI是一个强大的Minecraft插件开发接口&#xff0c;它为开发者提供了创建自定义插件…

作者头像 李华