写点什么

2 年 Java,面试蚂蚁金服总结

作者:Java高工P7
  • 2021 年 11 月 10 日
  • 本文字数:2193 字

    阅读完需:约 7 分钟

1、HashSet 可以接受 null 值,有且只有一个


2、TreeSet 默认不可以接受 null 值,会直接抛出空指针异常


set 里没有重复数据,treeSet 里连虚无都没有。


HashMap 如何解决冲突,扩容机制


烂大街的问题,问哪答哪吧。这样的东西就是靠背。


HashMap 的内部结构其实是数组+链表(java8 后如果长度大于 8 则转换为红黑树)。HashMap 初始化时,默认有 16 个 hash 槽。


存入对象时,首先,通过对象的 hashCode,定位到 hash 槽。如果多个对象同时落入同一个槽,那么就会使用链表解决本槽上的冲突。


HashMap 在创建时,会有一个负载因子。每次 put 操作,都会检查当前容量是否会超出阈值(initailCapacity*loadFactor)。如果超出,则扩容为当前的两倍。扩容后,数据需要重新散列,也就是 transfer 方法。


经验:resize 非常耗时,所以如果能够提前预估容量,可以把 initailCapacity 提前固定下来。


ConcurrentHashMap 如何做到高并发的


简单点说,使用了分段锁(分离锁)。每一把锁用于锁住容器中的一部分数据,减少线程间对锁的竞争。


这道题往深里问会死人的,篇幅有限,不啰嗦。


线程池平常怎么用


普通的场景,使用工厂类 Executors 创建就可以了。常用的有 Single、Fixed、Cached 三种。


更多时候,为了更精细的控制,会直接对 ThreadPoolExecutor 类进行定制。阿里的规范也要求这么搞(当然要舔一舔),我尤其关心其中的阻塞队列和饱和策略。


当然,你只有对阻塞队列和拒绝策略熟悉才能这么说。否则给自己挖坑就太不聪明了。


他们很喜欢你提到阿里规范,这让我觉得 jdk 设计的很 low


多个线程等待到某一节点然后统一放行有几种实现方式?


最经典的就是 CountDownLatch,主线程阻塞在 await 方法,每个线程调用 countDown。可以解决一些经典的赛马问题。


还有一个变种就是 CyclicBarrier。每个线程都阻塞在 await 方法,达到一定阈值集体放行。


另外还可以使用一些较初级的 api,比如 Thread 的 join 方法。Future 的 get 方法等。复杂不推荐。


也可以答 sleep 啊。有什么问题么?我用 while 等待一个变量也是可以的,但我为什么要这么做?


数据库索引结构


B+ Tree,为了适应缓慢的磁盘而生的一种索引结构。必须保证按照索引的最左前缀查询。


Hash?和 HashMap 类似,处理冲突的方式是链表


pg 的索引结构就多了去了。Mysql 这么少怎么感觉怪怪的?难道要我回答存储引擎的区别?


select * from t where a=? and b>? order by c limit 0,100 如何加索引


知道这个就结论就行了=>


当 order by 字段出现在 where 条件中时,才会利用索引而无需排序操作。其他情况,order by 不会出现排序操作。


按照最左原则,我可以创建 (a,b) 的索引。


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


一个表只能有一个聚簇索引。主索引文件和数据文件为同一份文件,默认的 InnoDB 就支持聚簇索引,B+ Tree 的叶子节点上的 data 就是数据本身。


而 MyISAM 就不支持聚簇索引,它的叶子结点存放的不是数据本身,而是数据存放的地址。在文件结构上,会分为一个索引文件、一个数据文件。


对编程来说没什么鸟用。


了解 CAP 吗?redis 里的 CAP 是怎样的?


  • Consistency 一致性

  • Availability 可用性

  • Partition tolerance 分区容错

  • 一般,都在 C、A 之间进行权衡。


redis 简单主从模式侧重于 CP 的,即对于一致性要求较高。


redis-cluster,则属于 AP 类型,更加强调可用性


cap 就是帽子,绿油油的那种


如何理解幂等?项目中接口的幂等是如何做的?


幂等是指多次执行,影响相同。


比如大多数 Post 操作,重复提交订单等,最终只会有一个订单生成成功。还有一种情况就是消息,由于大多数 MQ 之保证 at least once,所以消息有时会重复。


1、对于 Post 请求,我一般在请求成功后,强制跳转到其他页面,避免刷新提交。


2、复杂的操作一般使用流水号来实现。


3、某些不带流水号的消息,处理的时候,就要进行多次校验和 check,甚至引入消息状态表,来保证幂等。


就如同表白,每次表白都是被拒绝,因为我就是那个 id!


解释下乐观锁悲观锁


悲观锁总是假设情况最坏,每次操作数据都认为别人会修改,就加锁来保证安全。后面的访问者只能等待。数据库中的行锁、表锁,java 中的同步关键字等,都属于悲观锁。


乐观锁正好相反,总是假设最好的情况,不用对数据加锁,但多了一次额外的判断操作。比如 concurrent 包里大量的 CAS 操作、判断新旧版本号机制等


【一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
复制代码



悲观锁是老婆,有你独占;乐观锁是炮友,按预约规划


JVM 判断对象是否回收?


答案就是 GC roots。也就是从根对象出发,没有任何一个对象引用到它,那么就判断这个对象是不可达的。


通常被骂“断子绝孙”的人,就是要被回收的 root


GCROOT 有哪些?


1 、 虚拟机栈(栈帧中的本地变量表)中引用的对象。


2、 本地方法栈中 JNI(即一般说的 native 方法)引用的对象。


3、 方法区中的静态变量和常量引用的对象。


4、活跃线程的引用对象


所以不要让他们过度繁殖。


反射能获得类里面方法的名称吗?参数名称呢?参数类型呢?


都可以。


java8 以后,通过 Parameter 类获取参数名称。但有前提,需要加编译开关。


javac -parameters


默认是关闭的,干!


问题都偏到月球上去了


动态代理的实现方式?CgLib 和 jdk 的代理有什么区别?


java 中通过实现 InvocationHandler 接口来实现动态代理,然后使用 Proxy 将其初始化。


Cglib 使用了 ASM 自己吗生成框架,可以代理普通类,但代理不了 final 类,而 jdk 的只能代理接口。


在 spring 里,cglib 胜出


分布式锁有哪些主流实现方式?redis 和 zk 锁有什么区别?


大体分为两类。


乐观锁:

用户头像

Java高工P7

关注

还未添加个人签名 2021.11.08 加入

还未添加个人简介

评论

发布
暂无评论
2年Java,面试蚂蚁金服总结