博客记录-day154-面试

一、面试

1、项目问题

1. 怎么防止重复下单?

✅如何解决消息重复消费、重复下单等问题?

防止重复下单可通过多种机制实现:唯一索引约束通过在订单表的用户ID、商品ID等字段建立唯一索引避免重复数据;分布式锁利用Redis或Zookeeper在下单前锁定资源,防止并发冲突;幂等性设计通过生成唯一订单号、Redis的SETNX命令或数据库事务结合唯一索引确保操作仅执行一次;Token令牌机制则要求客户端先获取一次性有效token,服务端校验后处理请求。

2. 采用REDIS分段消费做防超卖的具体机制?

✅库存扣减如何避免超卖和少卖?

Redis分段消费通过将库存拆分为多个子库存(如10个片段),利用DECR/DECRBY命令原子减库存,结合Lua脚本保证操作的原子性。用户下单时随机选择子库存扣减,当某个子库存耗尽时尝试其他片段,从而分散热点数据竞争,提升并发性能。

3. 是否有限流机制?

✅什么是限流?常见的限流算法有哪些?

常见的限流算法包括计数器、滑动窗口、漏桶和令牌桶算法。分布式限流可通过Redis结合Lua脚本实现,结合Sentinel或集群保障高可用;应用层限流则通过Servlet过滤器、Spring AOP或网关(如Gateway)实现,支持灵活应对不同场景的流量控制需求。

2、线程同步与并发编程

1. 还了解其他哪些线程同步方式?

✅线程同步的方式有哪些?

除synchronized外,Java还提供ReentrantLock、ReadWriteLock、StampedLock、Semaphore、CountDownLatch、CyclicBarrier、Phaser、Exchanger等同步工具。原子类(如AtomicInteger)和ThreadLocal通过无锁化或线程本地变量减少竞争,volatile关键字则保证可见性但不确保原子性。

2. SYNCHRONIZE如何保证原子性?

✅synchronized是如何保证原子性、可见性、有序性的?

synchronized通过监视器锁(Monitor)实现互斥,同一时刻仅允许一个线程进入同步块。字节码层面使用monitorenter和monitorexit指令标记同步块,JVM插入内存屏障防止指令重排,确保操作的原子性和可见性。

3. SYNCHRONIZE能否保证有序性?

✅synchronized是如何保证原子性、可见性、有序性的?

synchronized通过内存屏障禁止指令重排,保证同步代码块内的操作有序。其happens-before规则确保同一锁的解锁操作先于后续加锁操作,但对不同锁或非同步代码无效,可能存在跨锁重排。

4. 了解无锁化编程吗?有什么问题?

✅什么是CAS?存在什么问题?

无锁化编程通过CAS、原子类、写时复制等技术实现线程安全,但存在ABA问题(值变化后恢复导致误判)、自旋开销、单变量限制及活锁风险。例如,CAS失败时频繁重试可能浪费CPU资源,复合操作需额外设计保证原子性。

3、线程池

1. 线程池的原理是什么?

✅什么是线程池,如何实现的?

线程池通过核心线程、任务队列、最大线程数和拒绝策略管理任务。提交任务时,优先用核心线程处理;队列满后创建临时线程;资源耗尽则执行拒绝策略(如丢弃任务或抛出异常)。线程复用通过阻塞队列实现,减少线程创建销毁的开销。

2. 如何动态调整线程池参数?

可通过ThreadPoolExecutor的setCorePoolSize()【设置核心线程数】、setMaximumPoolSize()【设置最大线程数】等方法调整参数,或结合配置中心(如Nacos)实时更新。自适应方案监控队列长度和活跃线程数,动态优化参数以适应负载变化。

3. 如何监控线程池状态?

内置方法(如getActiveCount()【返回线程池中​​当前正在执行任务的线程的估计数量​ ​】、getQueue().size()【返回线程池工作队列中​​当前积压的任务数量】)获取实时指标,JMX通过MBean暴露监控数据。自定义监控可定时采集指标并集成Prometheus,分析线程池使用率、任务等待时间及拒绝量,结合Arthas等工具诊断异常。

4. 拒绝策略有哪些适用场景?

✅线程池的拒绝策略有哪些?

AbortPolicy抛出异常,适用于需明确感知任务拒绝的场景;CallerRunsPolicy在调用者线程执行任务,适合降级处理;DiscardPolicy直接丢弃任务,用于非关键数据(如日志);DiscardOldestPolicy移除旧任务优先处理新任务,适用于实时性要求高的场景。

4、JVM内存与垃圾回收

1. 对JVM内存模型(JMM)的了解?

✅什么是Java内存模型(JMM)?

JMM定义多线程内存访问规范,核心为主内存(共享变量)和工作内存(线程私有副本)。通过happens-before规则保证可见性与有序性,如监视器锁规则(解锁先于加锁)、volatile变量规则(写先于读)及传递性等。

2. 垃圾回收算法中标记清除GC Roots可以用哪个?

✅JVM如何判断对象是否存活?

标记阶段从GC Roots遍历可达对象并标记为存活,清除阶段回收未标记对象的内存。优点是实现简单,缺点是产生内存碎片且效率较低,需结合压缩算法(如标记-整理)优化。

3. 如何排查Full GC问题?

✅假设还有很多内存,有什么情况还会频繁fullgc?

通过GC日志分析频率和耗时,使用jmap生成堆转储,借助MAT工具定位内存泄漏或大对象。调整新生代与老年代比例、优化对象生命周期或升级硬件(如增加堆内存)是常见解决方案。

4. Full GC和Young GC的区别?

✅YoungGC和FullGC的触发条件是什么?

Young GC回收新生代(Eden/Survivor区),触发于空间不足,停顿短(毫秒级);Full GC回收整个堆及方法区,触发条件包括老年代不足、System.gc()调用等,停顿长(秒级),影响更大。

5、数据库与索引

1. 数据库索引类型有哪些?

✅什么是聚簇索引和非聚簇索引?

B-Tree索引支持等值和范围查询(如InnoDB主键);哈希索引仅等值查询(Memory引擎);全文索引用于文本搜索(InnoDB 5.6+);空间索引处理地理数据(R-Tree)。按物理结构分为聚集索引(数据与索引同序)和非聚集索引(索引与数据分离)。

2. 如何避免回表?

✅什么是回表,怎么减少回表的次数?

覆盖索引通过查询字段均包含在索引中,直接读取数据无需回表。优化联合索引设计(遵循最左前缀)、使用主键查询(InnoDB聚集索引)或索引下推(提前过滤数据)均可减少回表次数。

3. 主键一般用什么类型?分布式环境下自然ID的缺点?

✅MySQL的主键一定是自增的吗?

整型(自增ID)或UUID是常用主键。自然ID(如自增ID)在分布式系统中存在唯一性冲突、性能瓶颈(集中生成)、迁移困难及安全风险(易被猜测)等问题。

4. 分布式ID生成方式有哪些?

✅Leaf生成分布式ID的原理?

✅什么是雪花算法,怎么保证不重复的?

Snowflake算法生成趋势递增的64位ID(时间戳+机器ID+序列号);数据库号段模式预分配ID范围;Redis自增或Leaf、UidGenerator等系统提供高可用方案。UUID无序但全局唯一,适合非索引场景。

5. B+树为什么适合做索引?

✅什么是B+树,和B树有什么区别?

B+树高度平衡,支持高效范围查询(叶子节点链表连接);非叶子节点仅存键值,容纳更多索引项,降低树高;数据存储在叶子节点,磁盘I/O更少。相比B树,B+树分支因子更大,查询更稳定。

6. B+树如何保持有序?

✅InnoDB为什么使用B+树实现索引?

插入时定位叶子节点并保持有序,节点满则分裂并更新父节点;删除时合并或重分布键值,通过旋转维护平衡。非叶子节点分隔键确保左右子树有序,叶子节点链表支持顺序遍历。

7. B+树相比B树为什么更扁平?

B+树非叶子节点不存数据,可存更多键值,分支因子更高,树高更低。例如,相同节点大小下,B+树存储量是B树的两倍,减少磁盘访问次数,提升查询效率。

6、消息队列

1. 消息队列的使用场景?

✅为什么要使用消息队列?

消息队列用于日志异步处理、数据同步、分布式事务(如事务消息)、流量削峰、延迟任务调度、系统解耦及事件通知等场景,提升系统扩展性和可靠性。

2. 除了RocketMQ还了解哪些消息队列?

✅Kafka、ActiveMQ、RabbitMQ和RocketMQ都有哪些区别?

Kafka高吞吐适合日志和流处理;RabbitMQ基于AMQP,支持复杂路由;Pulsar支持存储计算分离和流批一体;ActiveMQ、NSQ、Redis Streams等各有适用场景,如ZeroMQ轻量级,适合内部通信。

3. Kafka如何保证消息不丢失?

✅Kafka如何保证消息不丢失?

生产者通过acks=all(全副本确认)、重试和幂等性避免丢失;Broker多副本(ISR机制)和持久化存储保障数据冗余;消费者手动提交offset并配合事务确保消费处理原子性。

4. Kafka的Offset有什么作用?

✅Kafka 中的Offset是什么?

Offset标记消费进度,支持手动/自动提交,存储于__consumer_offsets主题。它实现断点续传、消费重放及重平衡时的分区分配,监控Offset可分析消费延迟。

7、网络

1. 浏览器输入域名后的解析过程?

✅浏览器输入www.taobao.com回车之后发生了什么

浏览器解析URL后递归查询DNS:缓存→操作系统→路由器→ISP DNS→根域名服务器→顶级域名服务器→权威服务器,最终获取IP。随后三次握手建立TCP连接,发送HTTP请求,服务器响应后渲染页面,最后关闭连接。

2. 三次握手能否携带数据?

前两次握手(SYN和SYN+ACK)不携带数据,仅建立连接;第三次握手(ACK)确认连接建立,可携带数据,此时客户端进入ESTABLISHED状态,可发送请求。

3. 如何防御SYN攻击?

博客记录-day063-反射机制详解、SPI机制详解+TCP面试题 - 掘金

服务器端启用SYN Cookie、调整TCP参数(增大半连接队列、缩短超时)及限制单IP速率;网络层通过防火墙过滤异常流量;应用层使用CDN或代理隐藏真实服务器,分散攻击压力。客户端防护有限,主要依赖可信网络和代理。

4. 客户端能否做SYN攻击防御?

客户端无法直接防御针对服务器的SYN攻击,但可通过代理访问、检测异常连接或启用备用连接减少风险。企业网络可监控出站流量,防止内部主机发起攻击。

相关推荐
PPIO派欧云2 小时前
PPIO X OWL:一键开启任务自动化的高效革命
运维·人工智能·自动化·github·api·教程·ppio派欧云
一纸忘忧2 小时前
成立一周年!开源的本土化中文文档知识库
前端·javascript·github
吾日三省吾码4 小时前
GitHub Copilot (Gen-AI) 很有用,但不是很好
人工智能·github·copilot
Gladiator5756 小时前
博客记录-day155-力扣+面试
github
徐小夕9 小时前
写了一款3D可视化编辑器模版,开源!
前端·javascript·github
uhakadotcom9 小时前
持续写作的“农耕思维”:如何像农民一样播种,收获稳定成长与收入
后端·面试·github
服部9 小时前
如何查看指定作者在所有分支的提交记录
前端·git·github
小华同学ai10 小时前
2.1k star! 抓紧冲,DeepChat:连接AI与个人世界的智能助手的开源项目
人工智能·ai·开源·github·工具
互联网搬砖老肖12 小时前
运维打铁:域名详解及常见问题解决
运维·github