2026.4.28 d6

1. HashMap 的底层实现原理

JDK 1.8 之后:

  • 数据结构:数组 + 链表 + 红黑树
  • 数组:Node<K,V>[] table
  • 每个位置叫 桶(bucket)

流程:

  1. key → hash
  2. hash → (n - 1) & hash 定位数组下标
  3. 发生冲突:
    • 链表(长度 < 8)
    • 红黑树(长度 ≥ 8 且数组长度 ≥ 64) 关键点:
  • 负载因子(loadFactor)默认 0.75
  • 扩容:容量 × 2
  • 链表转红黑树阈值:8
  • 红黑树转链表阈值:6

2. put(k, v) 的流程

put(key, value)  
↓  
计算 hash(key)  
↓  
index = (n - 1) & hash  
↓  
判断 table[index] 是否为空  
↓  
为空 → 直接插入  
↓  
不为空
↓  
判断是否 key 相同  
↓  
相同 → 覆盖 value  
↓  
不同 → 插入链表 / 红黑树  
↓  
链表长度 ≥ 8 → 转红黑树  
↓  
size++  
↓  
是否超过阈值 threshold  
↓  
超过 → resize()

和 HashMap 的线程安全集合

ConcurrentHashMap

  • JDK1.7:Segment 分段锁
  • JDK1.8:CAS + synchronized,桶为空使用CAS操作,不为空加锁操作 Hashtable
  • 方法级 synchronized
  • 粗粒度锁,性能差 Collections.synchronizedMap
  • 本质:包装 HashMap
  • 整体加锁

AQS和ReentrantLock

AQS:Java 并发包里的一个同步器框架。 AQS = state 状态变量 + CLH 等待队列 + CAS 修改状态

AQS
├── state:同步状态
│   └── int 类型,表示锁是否被占用、资源数量等
│
├── CAS:修改 state
│   └── 保证并发安全
│
└── 等待队列
    └── 获取锁失败的线程进入队列等待

线程获取锁时,会先通过 CAS 修改 state,如果失败就进入队列排队,并通过 LockSupport.park 阻塞;释放锁时通过 unpark 唤醒后继节点。

AQS 使用模板方法模式,将 tryAcquire / tryRelease 等方法交给子类实现,从而支持 ReentrantLock、Semaphore、CountDownLatch 等不同同步器。

synchronized 锁升级流程

锁状态(从低到高)

无锁 → 偏向锁 → 轻量级锁 → 重量级锁

升级过程

  1. 无锁
    • 对象刚创建,没有竞争
  2. 偏向锁
    • 第一个线程进入,记录线程ID到对象头
    • 后续该线程进入不需要加锁(无CAS)
    • 适用于“单线程反复进入”
  3. 轻量级锁
    • 多线程竞争,但不激烈
    • 通过 CAS + 自旋 尝试获取锁
    • 避免线程阻塞
  4. 重量级锁
    • 自旋失败 or 竞争激烈
    • 升级为 OS 互斥锁(mutex)
    • 线程阻塞 + 上下文切换
  • 只能升级,不能降级
  • 目的:减少用户态 → 内核态切换

MySQL 优化方向

1. SQL 层

  • 避免 select *
  • 避免函数、计算导致索引失效
  • 使用覆盖索引

2. 索引层

  • 合理设计 联合索引(最左匹配)
  • 避免索引失效(隐式类型转换等)

3. 架构层

  • 读写分离
  • 分库分表
  • 缓存(Redis)

分库分表

垂直拆分(Vertical)

按“字段 ”拆

例:

user表 → user_basic + user_detail

特点:

  • 减少单表字段数
  • 提高缓存命中率

水平拆分(Horizontal)

👉 按“数据行”拆

例:

user_0, user_1, user_2 (按 user_id % 3)

特点:

  • 解决数据量过大
  • 提高并发

三、MySQL 事务隔离级别

四种隔离级别

隔离级别 能解决的问题
读未提交(RU)
读已提交(RC) 脏读
可重复读(RR) 脏读 + 不可重复读
串行化(Serializable) 脏读 + 不可重复读 + 幻读
  • 脏读:读到未提交数据
  • 不可重复读:查询同一行数据多次前后不一致
  • 幻读:相同的范围查询结果

Redis 持久化机制

RDB(快照)

  • 定时生成 dump.rdb
  • fork 子进程 + COW(写时复制) 优点:
  • 文件小,恢复快 缺点:
  • 数据可能丢失

AOF(日志)

  • 记录每次写操作 策略:
  • always(每次刷盘)
  • everysec(默认)
  • no(操作系统决定) 优点:
  • 数据更安全 缺点:
  • 文件大

混合持久化

  • RDB + AOF Redis 混合持久化是在 AOF rewrite 时,先生成 RDB 快照作为基础数据,再追加 AOF 增量日志。

恢复时先加载 RDB,再重放 AOF,兼顾恢复速度和数据安全性。

Redis 内存淘汰策略

不淘汰

  • noeviction

TTL相关

  • volatile-lru
  • volatile-lfu
  • volatile-random
  • volatile-ttl

全局淘汰

  • allkeys-lru
  • allkeys-lfu
  • allkeys-random

六、JVM 内存结构

JVM  
├── 堆(Heap)  
│   ├── 新生代(Eden + S0 + S1)  
│   └── 老年代  
├── 方法区(MetaSpace)  
├── 虚拟机栈(Java Stack)  
├── 本地方法栈  
└── 程序计数器

各区域作用

    • 存对象
    • GC主要区域
  • 方法区(MetaSpace)
    • 类信息、常量
  • 虚拟机栈
    • 方法调用、局部变量
  • 程序计数器
    • 记录当前执行字节码文件位置,方便线程切换后找到执行位置

常见垃圾回收算法

标记-清除

  1. 标记:标记所有存活对象
  2. 清除:回收未标记对象

复制算法

  1. 将内存分为两块(from / to,年轻代的S0和S1)
  2. 存活对象复制到另一块
  3. 清空原区域

标记-整理

  1. 标记存活对象
  2. 将存活对象向一端移动
  3. 清理边界外内存

常见收集器

  • Serial
  • ParNew
  • CMS
  • G1 把堆切成大小相等的 Region,每个 Region 在运行时动态充当 Eden / Survivor / Old之一,GC 优先回收性价比最高(性价比 = 可释放空间 / 预估回收耗时)的 Region,兼顾吞吐与延迟。
  • ZGC 用着色指针在对象引用里存元数据,配合读屏障,让几乎所有 GC 工作都与应用并发执行,STW 只剩根扫描的极短暂停。 ZGC着色指针这样存:reference → [状态位 | 对象地址]

传统GC时,移动对象时所有引用都需要更新,着色指针的好处是把对象的状态信息编码进引用中,使得 JVM 在访问对象时可以通过读屏障判断引用是否需要修正。

应用线程读取对象引用
        ↓
触发读屏障
        ↓
检查指针上的“颜色”
        ↓
判断对象是否已移动
        ↓
如果移动 → 修正为新地址
        ↓
继续执行

alt

面经链接

熙牛-电话一面 2026.4.17_牛客网

每日面经记录 文章被收录于专栏

记录每天Java和Agent面经学习

全部评论

相关推荐

拼多多暑期octimeline:拼多多服务端研发3.15&nbsp;笔试3.21&nbsp;一面4.1&nbsp;&nbsp;&nbsp;二面挂4.10&nbsp;一面4.17&nbsp;HR面4.23&nbsp;oc字节跳动在官网上投没反应,但是之前忽然看到个内推码,投了以后是日常实习,时间不合适。但是简历进了人才库,都是hr微信找我来面试的,由此开始了奇妙之旅。字节内部运转的很高效,佩服。3.16&nbsp;一面3.20&nbsp;二面挂4.15&nbsp;一面4.16&nbsp;二面4.20&nbsp;HR面&nbsp;&nbsp;HR面过了,但是承认有个拼多多的hr面也过了,字节表示需要明确选字节才走hc审批。部门很好,流程很快,但是权衡之下还是拒了。京东测开3.6&nbsp;&nbsp;&nbsp;一面3.9&nbsp;&nbsp;&nbsp;二面挂3.25&nbsp;一面挂(金融支付的测开面试官好凶,一问三不知,快要自闭了)美团(美团大BOSS~~)3.14&nbsp;笔试3.26&nbsp;小象超市一面挂3.30&nbsp;DAG引擎一面挂4.9&nbsp;&nbsp;&nbsp;金融业务一面挂4.17&nbsp;本地商业中台一面过然而并没有什么用,没回人才库,也没二面。感谢美团认可我,让我过一面。三次一面挂,一次一面过,屡败屡战,屡战屡败。美团提高了我的认知,磨炼了我的意志,美团万岁!OPPO3.31&nbsp;一面挂oppo的一面挂极大地刺激到了我,oppo不考笔试,只考项目,一直以为是大厂招聘要求高,原来是我太菜,我开始反思自己的不足之处,疯狂用ai升级项目,自救。感恩OPPO,点醒了沉睡的人蚂蚁集团3.19&nbsp;ai&nbsp;coding3.31&nbsp;一面挂&nbsp;&nbsp;这是一场kpi面,面试官没有开摄像头。3.31下午的OPPO,3.31晚上的蚂蚁kpi,让我彻底意识到自己的菜。虽然是一场kpi面,但是我忍了一个小时之后,等到反问环节,向面试官求助,请求指出我的问题在哪里。问题很多,面试官一针见血地指出了一个问题。我决定升级一下项目,而不是停留在学习项目、demo项目。但是第二天4.1上午10:00就是拼多多二面,我还没重构多少,就带着绝望的心情面拼多多。面到15min,我之前的玩具项目就被面试官问穿了,心态崩了,直接请求面试官给我的项目一点建议,指出我的问题,给点改进的方向。面试官很生气,说面试还没有结束,这种话本不应该现在说。但是既然说了,他还是指出了我的问题,给了几条建议、指点。最后还指出我不仅要提高项目,还要练习语言表达能力。感恩拼多多,彻底被多多征服了携程集团3.13&nbsp;&nbsp;笔试4道ac&nbsp;从此进入人才库阿里巴巴一开始不怎么会agent,没敢投。4.21&nbsp;测评4天后才笔试,下周一才面AI&nbsp;SRE,面着玩吧。华为软开4.8&nbsp;&nbsp;&nbsp;笔试4.10&nbsp;心理测评挂&nbsp;&nbsp;刚刚燃起的希望又幻灭了,“点击即送”的都没有把握住,又是一个小低谷。华为,我对你有了新的认识。招银网络4.15&nbsp;测评4.23&nbsp;一面&nbsp;今天刚面完,不知道结果同花顺4.15笔试、测评4.23喜提感谢信&nbsp;&nbsp;同花顺笔试还挺有意思海康威视4.16笔试、测评&nbsp;&nbsp;后续没反应简历挂:快手、哔哩哔哩、米哈游、美的集团、小米集团、滴滴、SHEIN总体来讲3.31-4.1痛苦达到了峰值,不在低谷中爆发,就在低谷中灭亡。求职好难,还过的去的bg让我在白板状态下也能获得面试机会,打了一年leetcode周赛让我对笔试和手撕无所畏惧,获得了有笔试门槛的公司的机会(拼多多、美团)。但是机会来了,面对机会,要想办法把握住。祝牛友们求职顺利,我这种水平一般的都能找到暑期,现在没找到的、还在煎熬着的牛友们也一定能行,不要放弃
江海寄余生Y:pdd挂了还可以捞嘛
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务