Java|最新蚂蚁Java岗面经:HashMap+多线程+缓存+中间件(含答案解析)( 二 )
(4)通常在 b+树上有两个头指针 , 一个指向根结点 , 一个指向关键字最小的叶子结 点;
(5)同一个数字会在不同节点中重复出现 , 根节点的最大元素就是 b+树的最大元 素 。
B+树相比于 B 树的查询优势:
(1)B+树的中间节点不保存数据 , 所以磁盘页能容纳更多节点元素 , 更“矮胖”;
(2)B+树查询必须查找到叶子节点 , B 树只要匹配到即可不用管元素位置 , 因此 B+ 树查找更稳定(并不慢);
(3)对于范围查找来说 , B+树只需遍历叶子节点链表即可 , B 树却需要重复地中序遍历 。
3、通过引入单向链表来解决 Hash 冲突 。 当出现 Hash 冲突时 , 比较新老 key 值是否相等 , 如果相等 , 新值覆盖旧值 。 如果不相等 , 新值会存入新的 Node 结点 , 指向老节点 , 形成 链式结构 , 即链表 。
当 Hash 冲突发生频繁的时候 , 会导致链表长度过长 , 以致检索效率低 , 所以 JDK1.8 之后引入了红黑树 , 当链表长度大于 8 时 , 链表会转换成红黑书 , 以此提高查询性能 。
蚂蚁二面
- 设计模式有哪些大类 , 及熟悉其中哪些设计模式?
- volatile 关键字 , 它是如何保证可见性 , 有序性?
- Java 的内存结构、堆分为哪几部分 , 默认年龄多大进入老年代?
- ConcurrentHashMap 如何保证线程安全 , jdk1.8 有什么变化?
- 为什么 ConcurrentHashMap 底层为什么要红黑树?
- 如何做的 MySQL 优化?
- 讲一下 oom 以及遇到这种情况怎么处理的 , 是否使用过日志分析工具?
2、volatile 可以保证线程可见性且提供了一定的有序性 , 但是无法保证原子性 。 在 JVM 底层volatile 是采用“内存屏障”来实现的 。
观察加入 volatile 关键字和没有加入 volatile 关键字时所生成的汇编代码发现 , 加入 volatile 关键字时 , 会多出一个 lock 前缀指令 。
lock 前缀指令实际上相当于一个内存屏障(也称内存栅栏) , 内存屏障会提供 3 个功能:
I. 它确保指令重排序时不会把其后面的指令排到内存屏障之前的位置 , 也不会把前面的指令排到内 存屏障的后面;即在执行到内存屏障这句指令时 , 在它前面的操作已经全部完成;
II. 它会强制将对缓存的修改操作立即写入主存;
III. 如果是写操作 , 它会导致其他 CPU 中对应的缓存行无效 。
3、Java 的内存结构:程序计数器、虚拟机栈、本地方法栈、堆、方法区 。
Java 虚拟机根据对象存活的周期不同 , 把堆内存划分为几块 , 一般分为新生代、老年代 和永久代 。
默认的设置下 , 当对象的年龄达到 15 岁的时候 , 也就是躲过 15 次 GC 的时候 , 他就会转移到老年代中去 , 既躲过 15 次 GC 之后进入老年代 。
蚂蚁三面
- 项目介绍
- 你们怎么保证 Redis 缓存和数据库的数据一致性?
- Redis 缓存雪崩?击穿?穿透?
- 你熟悉哪些消息中间件有做过性能比较?
看了以上的面试问题 , 你能答出来多少?进阿里是否真的有想象中的那么难?
我这里已经整理好了完整答案 , 还有许多大厂面试真题、技术分类面试题 , 供大家冲刺刷题用 。 需要的朋友 , 帮忙转发一下文章 , 私信“资料”获取