各场面试经验

Posted 十一vs十一

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了各场面试经验相关的知识,希望对你有一定的参考价值。

蚂蚁金服面经
1. ArrayList 和 LinkedList 区别?
ArrayList 是一个可改变大小的数组。当更多的元素加入到 ArrayList 中时,其大小将会动
态地增长。内部的元素可以直接通过 get 与 set 方法进行访问,因为 ArrayList 本质上就
是一个数组。
LinkedList 是一个双链表,在添加和删除元素时具有比 ArrayList 更好的性能.但在 get 与
set 方面弱于 ArrayList。当然,这些对比都是指数据量很大或者操作很频繁的情况下的对
比,如果数据和运算量很小,那么对比将失去意义。
2. 什么情况会造成内存泄漏?
在 Java 中,内存泄漏就是存在一些被分配的对象,这些对象有下面两个特点:
首先,这些对象是可达的,即在有向图中,存在通路可以与其相连;
其次,这些对象是无用的,即程序以后不会再使用这些对象。如果对象满足这两个条件,
这些对象就可以判定为 Java 中的内存泄漏,这些对象不会被 GC 所回收,然而它却占用内
存。
3. 什么是线程死锁,如何解决?
产生死锁的条件有四个:
l 互斥条件:所谓互斥就是进程在某一时间内独占资源。
l 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
l 不剥夺条件: 进程已获得资源,在末使用完之前,不能强行剥夺。l 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
线程死锁是因为多线程访问共享资源,由于访问的顺序不当所造成的,通常是一个线程锁
定了一个资源 A,而又想去锁定资源 B;
在另一个线程中,锁定了资源 B,而又想去锁定资源 A 以完成自身的操作,两个线程都想
得到对方的资源,而不愿释放自己的资源,造成两个线程都在等待,而无法执行的情况。
要解决死锁,可以从死锁的四个条件出发,只要破坏了一个必要条件,那么我们的死锁就
解决了。在 Java 中使用多线程的时候一定要考虑是否有死锁的问题。
4. 说一下 HashMap 以及它是否线程安全
HashMap 基于哈希表的 Map 接口的实现。
HashMap 中,null 可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为
null。
HashMap 中 hash 数组的默认大小是 16,而且一定是 2 的指数。Hashtable、HashMap
都使用了 Iterator。而由于历史原因,Hashtable 还使用了 Enumeration 的方式 。
HashMap 实现 Iterator,支持 fast-fail。
哈希表是由数组+链表组成的,它是通过把 key 值进行 hash 来定位对象的,这样可以提
供比线性存储更好的性能。HashMap 不是线程安全的。
5. 说一下 Innodb 和 MySIAM 的区别?
MyISAM 类型不支持事务处理等高级处理,而 InnoDB 类型支持。MyISAM 类型的表强
调的是性能,其执行数度比 InnoDB 类型更快,但是不提供事务支持,而 InnoDB 提供事
务支持以及外部键等高级数据库功能。
InnoDB 不支持 FULLTEXT 类型的索引。
InnoDB 中不保存表的具体行数,也就是说,执行 select count(*) from table 时,
InnoDB 要扫描一遍整个表来计算有多少行,但是 MyISAM 只要简单的读出保存好的行数
即可。注意的是,当 count(*)语句包含 where 条件时,两种表的操作是一样的。
对于 AUTO_INCREMENT 类型的字段,
InnoDB 中必须包含只有该字段的索引,但是在
MyISAM 表中,可以和其他字段一起建立联合索引。
DELETE FROM table 时,
InnoDB 不会重新建立表,而是一行一行的删除。LOAD TABLE FROM MASTER 操作对 InnoDB 是不起作用的,解决方法是首先把
InnoDB 表改成 MyISAM 表,导入数据后再改成 InnoDB 表,但是对于使用的额外的
InnoDB 特性(例如外键)的表不适用。
6. 访问淘宝网页的一个具体流程,从获取 IP 地址,到怎么返回相
关内容?
先通过 DNS 解析到服务器地址,然后反向代理、负载均衡服务器等,寻找集群中的一台
机器来真正执行你的请求。还可以介绍 CDN、页面缓存、Cookie 以及 session 等。
这个过程还包括三次握手、HTTP request 中包含哪些内容,状态码等,还有 OSI 七层分
层可以介绍。
服务器接到请求后,会执行业务逻辑,执行过程中可以按照 MVC 来分别介绍。
服务处理过程中是否调用其他 RPC 服务或者异步消息,这个过程包含服务发现与注册,消
息路由。
最后查询数据库,会不会经过缓存?是不是关系型数据库?是会分库分表还是做哪些操
作?
对于数据库,分库分表如果数据量大的话是有必要的,一般业务根据一个分表字段进行取
模进行分表,而在做数据库操作的时候,也根据同样的规则,决定数据的读写操作对应哪
张表。这种也有开源的实现的,如阿里的 TDDL 就有这种功能。分库分表还涉及到很多技
术,比如 sequence 如何设置 ,如何解决热点问题等。
最后再把处理结果封装成 response,返回给客户端。浏览器再进行页面渲染。7. 介绍一下并发
这里可以把整个并发的体系都说下,包括 volatile、synchronized、lock、乐观悲观锁、
锁膨胀、锁降级、线程池等。
8. 说一下关系型数据库和非关系型数据库的区别
非关系型数据库的优势:
性能:NOSQL 是基于键值对的,可以想象成表中的主键和值的对应关系,而且不需要经
过 SQL 层的解析,所以性能非常高。
可扩展性:同样也是因为基于键值对,数据之间没有耦合性,所以非常容易水平扩展。
使用场景:日志、埋点、论坛、博客等。
关系型数据库的优势:
复杂查询:可以用 SQL 语句方便的在一个表以及多个表之间做非常复杂的数据查询
事务支持:使得对于安全性能很高的数据访问要求得以实现。
使用场景:所有有逻辑关系的数据存储。
9. 如何访问链表中间节点
对于这个问题,我们首先能够想到的就是先遍历一遍整个的链表,然后计算出链表的长
度,进而遍历第二遍找出中间位置的数据。这种方式非常简单。
若题目要求只能遍历一次链表,那又当如何解决问题?
可以采取建立两个指针,一个指针一次遍历两个节点,另一个节点一次遍历一个节点,当
快指针遍历到空节点时,慢指针指向的位置为链表的中间位置,这种解决问题的方法称为快慢指针方法。
10. 说下进程间通信,以及各自的区别
进程间通信是指在不同进程之间传播或交换信息。方式通常有管道(包括无名管道和命名
管道)、消息队列、信号量、共享存储、Socket、Streams 等。
 
 
拼多多面经
一:看你在项目中用了 Redis,我们先聊聊 Redis 吧,常用的数据结构有哪几
种,在你的项目中用过哪几种,以及在业务中使用的场景。Redis 的 hash 怎
么实现的,rehash 过程讲一下和 JavaHashMap 的 rehash 有什么区别?
Redis cluster 有没有了解过,怎么做到高可用的?
1. 常用的数据结构:
字符串(String),散列/哈希(hash),列表(list),无序集合类型(set),有序集合类型
(sorted set)
2. Redis 的 Hash 实现:
Redis 散列/哈希是键值对的集合。Redis 散列/哈希是字符串字段和字符串值之间的映射,
但字段值只能是字符串,不支持其他类型。因此,他们用于表示对象。应用场景:存储用
户的基本信息,等等。
3. Redis cluster:
Redis 最开始使用主从模式做集群,若 master 宕机需要手动配置 slave 转为 master;后
来为了高可用提出来哨兵模式,该模式下有一个哨兵监视 master 和 slave,若 master 宕
机可自动将 slave 转为 master,但它也有一个问题,就是不能动态扩充;所以在 3.x 提出
cluster 集群模式。
Redis-Cluster 采用无中心结构,每个节点保存数据和整个集群状态,每个节点都和其他
所有节点连接。
4. 其结构特点:
l 所有的 Redis 节点彼此互联(PING-PONG 机制),内部使用二进制协议优化传输速度和
带宽。
l 节点的 fail 是通过集群中超过半数的节点检测失效时才生效。
l 客户端与 Redis 节点直连,不需要中间 proxy 层.客户端不需要连接集群所有节点,连接
集群中任何一个可用节点即可。
l Redis-cluster 把所有的物理节点映射到[0-16383]slot 上(不一定是平均分
配),cluster 负责维护 node<->slot<->value。
l Redis 集群预分好 16384 个桶,当需要在 Redis 集群中放置一个 key-value 时,根
据 CRC16(key) mod 16384 的值,决定将一个 key 放到哪个桶中。
二:Redis 集群和哨兵机制有什么区别?Redis 的持久化机制了解吗?你们在
项目中是怎么做持久化的?遇到过 Redis 的 hotkey 吗?怎么处理的?
1. Redis 集群和哨兵机制有什么区别?
谈到 Redis 服务器的高可用,如何保证备份的机器是原始服务器的完整备份呢?这时候就
需要哨兵和复制。
l 哨兵(Sentinel):可以管理多个 Redis 服务器,它提供了监控,提醒以及自动的故障
转移的功能。
l 复制(Replication):则是负责让一个 Redis 服务器可以配备多个备份的服务器。
l Redis 正是利用这两个功能来保证 Redis 的高可用。
2. Redis 哨兵主要功能
l 集群监控:负责监控 Redis master 和 slave 进程是否正常工作。
l 消息通知:如果某个 Redis 实例有故障,那么哨兵负责发送消息作为报警通知给管理
员。
l 故障转移:如果 master node 挂掉了,会自动转移到 slave node 上。
l 配置中心:如果故障转移发生了,通知 client 客户端新的 master 地址。
3. Redis 哨兵的高可用
原理:当主节点出现故障时,由 Redis Sentinel 自动完成故障发现和转移,并通知应用
方,实现高可用性。这个就是哨兵用来判断节点是否正常的重要依据,涉及两个新的概念:主观下线和客观下
线。
l 主观下线:一个哨兵节点判定主节点 down 掉是主观下线。
l 客观下线:只有半数哨兵节点都主观判定主节点 down 掉,此时多个哨兵节点交换主
观判定结果,才会判定主节点客观下线。
原理:基本上哪个哨兵节点最先判断出这个主节点客观下线,就会在各个哨兵节点中发起
投票机制 Raft 算法(选举算法),最终被投为领导者的哨兵节点完成主从自动化切换的过
程。
4. Redis 主从复制、哨兵和集群这三个有什么区别?
主从复制是为了数据备份,哨兵是为了高可用,Redis 主服务器挂了哨兵可以切换,集群
则是因为单实例能力有限,搞多个分散压力,简短总结如下:
l 主从模式:备份数据、负载均衡,一个 Master 可以有多个 Slaves。
l sentinel 发现 master 挂了后,就会从 slave 中重新选举一个 master。l cluster 是为了解决单机 Redis 容量有限的问题,将数据按一定的规则分配到多台机
器。
l sentinel 着眼于高可用,Cluster 提高并发量。
1. 主从模式:读写分离,备份,一个 Master 可以有多个 Slaves。
2. 哨兵 sentinel:监控,自动转移,哨兵发现主服务器挂了后,就会从 slave 中重新选举
一个主服务器。
3. 集群:为了解决单机 Redis 容量有限的问题,将数据按一定的规则分配到多台机器,内
存/QPS 不受限于单机,可受益于分布式集群高扩展性。
三:Redis 是单线程的吗?单线程为什么还这么快?讲一讲 Redis 的内存模
型?
Redis 内存划分:
Redis 作为内存数据库,在内存中存储的内容主要是数据(键值对);通过前面的叙述可以
知道,除了数据以外,Redis 的其他部分也会占用内存。
Redis 的内存占用主要可以划分为以下几个部分:
1. 数据
作为数据库,数据是最主要的部分;这部分占用的内存会统计在 used_memory 中。
Redis 使用键值对存储数据,其中的值(对象)包括 5 种类型,即字符串、哈希、列表、
集合、有序集合。这 5 种类型是 Redis 对外提供的,实际上,在 Redis 内部,每种类型可
能有 2 种或更多的内部编码实现;此外,Redis 在存储对象时,并不是直接将数据扔进内
存,而是会对对象进行各种包装:如 redisObject、SDS 等;这篇文章后面将重点介绍Redis 中数据存储的细节。
2. 进程本身运行需要的内存
Redis 主进程本身运行肯定需要占用内存,如代码、常量池等等;这部分内存大约几兆,
在大多数生产环境中与 Redis 数据占用的内存相比可以忽略。这部分内存不是由 jemalloc
分配,因此不会统计在 used_memory 中。
补充说明:除了主进程外,Redis 创建的子进程运行也会占用内存,如 Redis 执行 AOF、
RDB 重写时创建的子进程。当然,这部分内存不属于 Redis 进程,也不会统计在
used_memory 和 used_memory_rss 中。
3. 缓冲内存
缓冲内存包括客户端缓冲区、复制积压缓冲区、AOF 缓冲区等;其中,客户端缓冲存储客
户端连接的输入输出缓冲;复制积压缓冲用于部分复制功能;AOF 缓冲区用于在进行
AOF 重写时,保存最近的写入命令。在了解相应功能之前,不需要知道这些缓冲的细节;
这部分内存由 jemalloc 分配,因此会统计在 used_memory 中。
4. 内存碎片
内存碎片是 Redis 在分配、回收物理内存过程中产生的。例如,如果对数据的更改频繁,
而且数据之间的大小相差很大,可能导致 Redis 释放的空间在物理内存中并没有释放,但
Redis 又无法有效利用,这就形成了内存碎片。内存碎片不会统计在 used_memory 中。
内存碎片的产生与对数据进行的操作、数据的特点等都有关;此外,与使用的内存分配器
也有关系:如果内存分配器设计合理,可以尽可能的减少内存碎片的产生。后面将要说到的 jemalloc 便在控制内存碎片方面做的很好。
如果 Redis 服务器中的内存碎片已经很大,可以通过安全重启的方式减小内存碎片:因为
重启之后,Redis 重新从备份文件中读取数据,在内存中进行重排,为每个数据重新选择
合适的内存单元,减小内存碎片。
四:我看你还用了 RabbitMQ,简单说一下 RabbitMQ 的工作原理?如何保
证消息的顺序执行?Kafka 了解吗?和 RabbitMQ 有什么区别?你为啥不用
kafka 来做,当时怎么考虑的?
组成部分说明如下:
l Broker:消息队列服务进程,此进程包括两个部分:Exchange 和 Queue。
l Exchange:消息队列交换机,按一定的规则将消息路由转发到某个队列,对消息进行
过虑。
l Queue:消息队列,存储消息的队列,消息到达队列并转发给指定的消费方。
l Producer:消息生产者,即生产方客户端,生产方客户端将消息发送到 MQ。
l Consumer:消息消费者,即消费方客户端,接收 MQ 转发的消息。
消息发布接收流程:
-----发送消息-----
1. 生产者和 Broker 建立 TCP 连接。
2. 生产者和 Broker 建立通道。
3. 生产者通过通道消息发送给 Broker,由 Exchange 将消息进行转发。
4. Exchange 将消息转发到指定的 Queue(队列)----接收消息-----
1. 消费者和 Broker 建立 TCP 连接。
2. 消费者和 Broker 建立通道。
3. 消费者监听指定的 Queue(队列)。
4. 当有消息到达 Queue 时 Broker 默认将消息推送给消费者。
5. 消费者接收到消息。
五:我看你简历里说熟悉计算机网络,来聊一聊计算机网络吧。了不了解
tcp/udp,简单说下两者的区别?
1. 区别:
l TCP 面向连接(如打电话要先拨号建立连接);UDP 是无连接的,即发送数据之前不
需要建立连接。
l TCP 提供可靠的服务。也就是说,通过 TCP 连接传送的数据,无差错、不丢失、不重
复,且按序到达,UDP 尽最大努力交付,即不保证可靠交付。
l TCP 面向字节流,实际上是 TCP 把数据看成一连串无结构的字节流;UDP 是面向报文
l UDP 没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很
有用,如 IP 电话,实时视频会议等)。
l 每一条 TCP 连接只能是点到点的,UDP 支持一对一、一对多、多对一和多对多的交
互通信。
l TCP 首部开销 20 字节;UDP 的首部开销小,只有 8 个字节。
l TCP 的逻辑通信信道是全双工的可靠信道,UDP 则是不可靠信道。六:两次握手为什么不可以?为什么要四次挥手?
采用三次握手是为了防止失效的连接请求报文段突然又传送到主机 B,因而产生错误。失
效的连接请求报文段是指:主机 A 发出的连接请求没有收到主机 B 的确认,于是经过一段
时间后,主机 A 又重新向主机 B 发送连接请求,且建立成功,顺序完成数据传输。考虑这
样一种特殊情况,主机 A 第一次发送的连接请求并没有丢失,而是因为网络节点导致延迟
达到主机 B,主机 B 以为是主机 A 又发起的新连接,于是主机 B 同意连接,并向主机 A 发
回确认,但是此时主机 A 根本不会理会,主机 B 就一直在等待主机 A 发送数据,导致主机
B 的资源浪费。
TCP 关闭链接四次握手原因在于 TCP 链接是全双工通道,需要双向关闭。client 向 server
发送关闭请求,表示 client 不再发送数据,server 响应。此时 server 端仍然可以向 client
发送数据,待 server 端发送数据结束后,就向 client 发送关闭请求,然后 client 确认。
七:TCP 怎么保证有序传输的?
l 应用数据被分割成 TCP 认为最适合发送的数据块。
l 超时重传:当 TCP 发出一个段后,它启动一个定时器,等待目的端确认收到这个报文
段。如果不能及时收到一个确认,将重发这个报文段。
l TCP 给发送的每一个包进行编号,接收方对数据包进行排序,把有序数据传送给应用
l 校验和:TCP 将保持它首部和数据的检验和。这是一个端到端的检验和,目的是检测
数据在传输过程中的任何变化。如果收到段的检验和有差错,TCP 将丢弃这个报文段
和不确认收到此报文段。l TCP 的接收端会丢弃重复的数据。
l 流量控制:TCP 连接的每一方都有固定大小的缓冲空间,TCP 的接收端只允许发送端
发送接收端缓冲区能接纳的我数据。当接收方来不及处理发送方的数据,能提示发送
方降低发送的速率,防止包丢失。TCP 使用的流量控制协议是可变大小的滑动窗口协
议。
l 拥塞控制:当网络拥塞时,减少数据的发送。
八:time_wait 状态,这个状态出现在什么地方,有什么用?
1. 为实现 TCP 全双工连接的可靠释放
当服务器先关闭连接,如果不在一定时间内维护一个这样的 TIME_WAIT 状态,那么当被动关
闭的一方的 FIN 到达时,服务器的 TCP 传输层会用 RST 包响应对方,这样被对方认为是
有错误发生,事实上这只是正常的关闭连接工程,并没有异常。
2. 为使过期的数据包在网络因过期而消失
在这条连接上,客户端发送了数据给服务器,但是在服务器没有收到数据的时候服务器就
断开了连接。
现在数据到了,服务器无法识别这是新连接还是上一条连接要传输的数据,一个处理不当
就会导致诡异的情况发生。
九:HTTP 与 HTTPS 有啥区别?HTTPS 是怎么做到安全的?
HTTPS 安全的原因:
HTTPS 把 HTTP 消息进行加密之后再传送,这样就算坏人拦截到了,得到消息之后也看不懂,这样就做到了安全,具体来说,HTTPS 是通过对称加密和非对称加密和 hash 算法共
同作用,来在性能和安全性上达到一个平衡,加密是会影响性能的,尤其是非对称加密,
因为它的算法比较复杂,那么加密了就安全了吗?不是的,HTTPS 除了对消息进行了加密
以外还会对通信的对象进行身份验证。
HTTPS 并不是一种新的协议,而是使用了一种叫做 TLS(Transport layer secure)的安
全层,这个安全层提供了数据加密的支持,让 HTTP 消息运行在这个安全层上,就达到了
安全,而运行在这个安全层上的 HTTP 就叫做 HTTPS。
十、还有点时间,写个题吧
leetcode406. 根据身高重建队列
假设有打乱顺序的一群人站成一个队列。 每个人由一个整数对(h, k)表示,其中 h 是这个
人的身高,k 是排在这个人前面且身高大于或等于 h 的人数。 编写一个算法来重建这个队
列。
注意:
总人数少于 1100 人。
示例
输入:
[[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]]
输出:
[[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]]思路:
第一步排序:
people:
[[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]]
排序后:
[[7,0], [7,1], [6,1], [5,0], [5,2], [4,4]]
然后从数组 people 第一个元素开始,放入到数组 result 中,放入的位置就是离 result 开
始位置偏移了元素第二个数字后的位置。如下:
1. people: [7,0]
插入到离开始位置偏移了 0 个距离的位置。
result: [[7,0]]
2. people: [7,1]
插入到离开始位置偏移了 1 个距离的位置,即插入到[7,0]的后面。
result: [[7,0], [7,1]]
3. people: [6,1]
插入到离开始位置偏移了 1 个距离的位置,即插入到[7,0]的后面。
result: [[7,0], [6,1], [7,1]]
4. people: [5,0]
插入到离开始位置偏移了 0 个距离的位置,即插入到[7,0]的前面。result: [[5,0], [7,0], [6,1], [7,1]]
5. people: [5,2]
插入到离开始位置偏移了 2 个距离的位置,即插入到[7,0]的后面。
result: [[5,0], [7,0], [5,2], [6,1], [7,1]]
6. people: [4,4]
插入到离开始位置偏移了 4 个距离的位置,即插入到[6,1]的后面。
result: [[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]]
这种算法体现了元素第二个数字与其插入位置的关系,所以通过简单的一个 for 循环就可
 
 
 
 
 
快手面经
1. Spring 原理,Spring IOC、AOP
这个问题最好可以多说一点,比如对于 IOC,不妨把 Bean 如何加载、如何初始化以及如
何注册到 IOC 容器中的详细过程说一下,涉及 BeanDefinition、BeanFactory 也深入细
节聊一下。
2. 一个请求过来在 Spring 中发生了哪些事情?
这个问题不妨把一个请求过来 在 TCP 层面上建立连接、操作系统如何处理连接、Web 容
器器接收到连接对象后做了哪些事情、Spring 如何对接收到的请求进⾏处理都说一下,
当然最终还是 落在 Spring 容器内部如何处理一个请求,这个过程一定要说清楚,需要体
现细节。在说前面的内容的时候,可以放心面试官不会打断你。
3. 手写一个单例
这个基本上大多数公司都会考察的。要写一个 基于懒汉式的 双重检测的单例。单例有三
个比较关键的点:
l 私有构造方法,避免外部 new 出对象;
l 保证唯一性;
l 提供一个全局访问点。
另外懒汉式双重检测的实现方式有三点需要注意的地方:
l 全局访问点必须是静态的,外界使用可以通过类直接调用;l 在进入锁之后还需要校验;
l 保存单例例对象的私有变量一定要用 volatile 修饰,这个地方 可以多说一些,比如
volatile 防止指令重排序,保证内存可见性(JVM 层面 和 CPU 层面 可以分别说)。
volatile 这个地方能说的东西还是很多的,基本上可以与面试官再聊二十分钟了。
4. HashMap
对于 HashMap 其实一般高级岗位及以上不再会问这个东西了,一旦问了,肯定不是让
你只说一下数组+链表的。对于它的实现,不同版本实现方式不一样。
在 jdk1.8 之后,HashMap 除了数组+链表之外,引入了红黑树。那么好了,你需要说明
对于引入了红黑树的 HashMap 如何 put 一个元素,以及链表是在何时转化为红黑树
的。比如首先需要知道这个元素落在哪一个数组⾥,获取 hashcode 后并不是对数组长度
取余来确定的,而是高低位异或求与来得到的。这个地方首先得知道 异或、与是做什么样
的运算的,然后说一下在 HashMap 中的实现,比如 hashcode 无符号右移 16 位后和原
hashcode 做异或运算,这相当于把 hashcode 的高 16 位拿过来 和 hashcode 的 低
16 位 做异或运算,因为无符号右移后 前面高 16 位都补零,这就是前面说的 "高低位异
或“,进而是 ”求与“,和谁求与呢,和 数组长度减 1 求与。
说到这⾥起码能够证明你是看过源码的,接下来说说你的思考。
比如 我们知道对于 HashMap 初始化容量决定了数组大小,一般我们对于数组这个初始
容量的设置是有规律的,它应该是 2^n 。这个初始容量的设置影响了 HashMap 的效
率,那又涉及到影响 HashMap 效率的主要因素,比如初始容量和负载因子。当已用数组达到容量与负载因子的乘积之后会进行一个 rehash 的过程,这个地方涉及到的 如何
rehash 及各种算法如果有时间也是可以说的,没有时间不说也没有关系。回到刚才说的
2^n, 可以说说它为什么是 2^n。当我们说什么东西为什么是这样的时候,我们一般从两
个角度考虑,一个是这样做有什么好处,另一个是不这样做有什么坏处。我们刚才说到”
求与“这个过程,如果不是 2^n, 会导致较多的哈希碰撞(具体原因 可以自己分析一下 或
者百度一下),这个会影响 HashMap 的效率。
说完上面这些,既表明你看过源码,又表明你有自己的思考了,当然也可以进一步说说它
是在什么条件下以及 如何进行扩容的(如果时间允许,并且面试官也有耐心继续听下
去)。对于 put 操作,这才只是第一步,找到数组的位置,接下来 要看这个位置也没有元
素,如果没有,直接放进去就可以,如果有,要看怎么放进去,jdk1.8 中 对于 HashMap
的实现中,是基于 Node(链表节点) 和 TreeNode(红黑树节点) 的,当然它们继承了
Entry。那么 如果数组当前位置已经有了元素,就得知道这个元素 是 链表的节点还是红
黑树的节点,以便便 进一步确认接下来要 put 的元素 是以链表的方式插入还是以红黑树
的方式插入,这个地方 在源码中 进⾏了一个类型的判断,如果是链表的节点,就以链表
的方式把要 put 的节点插入到 next 为 null 的节点上,如果是红黑树的节点,就要以红黑
树的方式插入一个节点。
5. Java1.8 为什么要引入红黑树?如何在红黑树中插入一个节点?
对于这两个问题,首先,引入红黑树的好处是为了提高查询效率,要说出 O(log2(n)),但
是 在提高查找效率的同时也在插入的时候更加耗时,那可以说一下为什么更加耗时,自然
带出第二个问题,如何在红黑树中插入一个节点,比如当插入一个节点的时候我们会默认它是红色的(这个地方可以结合红黑树特点说一下我们为什么默认它是红色的,从黑色高度
以及相邻两节点不同为红色入手),插入后如果父节点是黑色的 就不需要动了了,但假如
是红色的,就需要进⾏左旋和右旋操作,如果很了解,可以细说左旋右旋如何实现,如果
不不是很了了解,到此为止也 ok。
说到这⾥,我们忽略略了一个重要的点,就是链表转换为红黑树的条件,说出链表长度到
8(相当于红黑树开始第四层) 以及数组大小达到 64 就已经够了了,也可以进一步说一下
链表是如何转换为红黑树的。说完也可以说一下 ConcurrentHashMap 中也是一样的,
然后接下来就引入对 ConcurrentHashMap 的理解,比如在什么地方会涉及到线程安全问
题以及 ConcurrentHashMap 是如何解决的,说说 CAS,说完 CAS 再说说 AQS,自由发
挥吧。
6. JVM 四种引用类型
这个问题比较简单,强引用、弱引用、软引用、虚引用,说一下它们各自的特点和 GC 对
它们的不同处理方式,再说一下常见的应用场景 或者 jdk 的实现中对它们的使用,比如
ThreadLocal 的静态内部类 ThreadLocalMap,它的 Key 是弱引用的,也可以说一下 在
你的理解中为什么它是弱引用的,假如不是会怎么样。
7. SpringBoot 启动过程
这个主要是从它基于 Spring 的事件发布和监听机制开始说起 就没什么问题。
8. 类加载过程加载、链接、初始化,链接又分为验证准备和解析,每一个阶段是做了什么要说清楚。
Object a = new Object();
这⾏代码做了了哪些事情,需要从类加载开始说起,这个相
当于上面问题的延续,所以 一定要清楚 每一个环节 做了哪些事情的,否则这个问题不可
能说清楚。说完类加载的过程 再说一下 开辟内存空间、初始化内存空间以及把内存地址
赋值给变量 a,接下来可以进一步说一下 JVM 或者 CPU 层面对指令的优化,以及在某些
时刻我们需要避免它做这样的优化,比如在单例中我们的实例需要用 volatile 修饰 避免指
令重排序(可以说一下 在 new 一个对象的过程中如果指令重排序了会导致什么结果)。
9. 说说 Netty
从 NIO 开始说肯定是没错的,再说说 Netty 的实现方式,以及它除了 IO 之外还干了哪些
事情。
10. 消息队列的熟练程度,比如问问 Kafka 分区,如何分区等
在 Kafka 实际生产过程中,每个 topic 都会有 多个 partitions。
1. 多个 Partitions 有什么好处?
l 多个 partition ,能够对 broker 上的数据进行分片,通过减少消息容量
来提升 IO 性能;
l 为了提高消费端的消费能力,一般情况下会通过多个 conusmer 去消费
同一个 topic 中的消息,即实现消费端的负载均衡。
2. 针对多个 Partition,消费者该消费哪个分区的消息?Kafka 存在 消费者组 group.id 的概念,组内的所有消费者协调在一起来消
费订阅的 topic 中的消息(消息可能存在于多个分区中)。那么同一个
group.id 组中的 consumer 该如何去分配它消费哪个分区里的数据。
针对下图中情况,3 个分区(test-0 ~ test-3),3 个消费者(ConsumerA ~
C),哪个消费者应该消费哪个分区的消息呢?
对于如上这种情况,3 个分区,3 个消费者。这 3 个消费者都会分别去消费
test 中 topic 的 3 个分区,也就是每个 Consumer 会消费一个分区中的消
息。
如果 4 个消费者消费 3 个分区,则会有 1 个消费者无法消费到消息;如果
2 个消费者消费 3 个分区,则会有 1 个消费者消费 2 个分区的消息。针对
这种情况,分区数 和 消费者数 之间,该如何选择?此处就涉及到 Kafka 消
费端的分区分配策略了。1. 什么是分区分配策略
通过如上实例,我们能够了解到,同一个 group.id 中的消费者,对于一个
topic 中的多个 partition 中的消息消费,存在着一定的分区分配策略。
在 Kafka 中,存在着两种分区分配策略。一种是 RangeAssignor 分配策略
(范围分区),另一种是 RoundRobinAssignor 分配策略(轮询分区)。默认采用
Range 范围分区。 Kafka 提供了消费者客户端参数
partition.assignment.strategy 用来设置消费者与订阅主题之间的分区分配策
略。默认情况下,此参数的值为:
org.apache.kafka.clients.consumer.RangeAssignor,即采用
RangeAssignor 分配策略
RangeAssignor 范围分区
Range 范围分区策略是对每个 topic 而言的。首先对同一个 topic 里面的分
区按照序号进行排序,并对消费者按照字母顺序进行排序。假如现在有 10 个
分区,3 个消费者,排序后的分区将会是 0,1,2,3,4,5,6,7,8,9;消费者排序完之
后将会是 C1-0,C2-0,C3-0。通过 partitions 数/consumer 数 来决定每个消
费者应该消费几个分区。如果除不尽,那么前面几个消费者将会多消费 1 个分
区。
例如,10/3 = 3 余 1 ,除不尽,那么 消费者 C1-0 便会多消费 1 个分区,
最终分区分配结果如下:C1-0
消费 0,1,2,3 分区
C2-0
消费 4,5,6 分区
C3-0
消费 7,8,9 分区(如果有 11 个分区的话,C1-0 将消费 0,1,2,3 分区,C2-0 将消费 4,5,6,7 分
区 C3-0 将消费 8,9,10 分区)
Range 范围分区的弊端:
如上,只是针对 1 个 topic 而言,C1-0 消费者多消费 1 个分区影响不是很
大。如果有 N 多个 topic,那么针对每个 topic,消费者 C1-0 都将多消费
1 个分区,topic 越多,C1-0 消费的分区会比其他消费者明显多消费 N 个分
区。这就是 Range 范围分区的一个很明显的弊端了
由于 Range 范围分区存在的弊端,于是有了 RoundRobin 轮询分区策略,
如下介绍↓↓↓
RoundRobinAssignor 轮询分区
RoundRobin 轮询分区策略,是把所有的 partition 和所有的 consumer 都
列出来,然后按照 hascode 进行排序,最后通过轮询算法来分配 partition
给到各个消费者。
轮询分区分为如下两种情况:l 同一消费组内所有消费者订阅的消息都是相同的。
l 同一消费者组内的消费者锁定月的消息不相同。
如果同一消费组内,所有的消费者订阅的消息都是相同的,那么 RoundRobin
策略的分区分配会是均匀的。
例如:同一消费者组中,有 3 个消费者 C0、C1 和 C2,都订阅了 2 个主题
t0 和 t1,并且每个主题都有 3 个分区(p0、p1、p2),那么所订阅的所以分
区可以标识为 t0p0、t0p1、t0p2、t1p0、t1p1、t1p2。最终分区分配结果如
下:
消费者 C0
消费 t0p0 、t1p0 分区
消费者 C1
消费 t0p1 、t1p1 分区
消费者 C2
消费 t0p2 、t1p2 分区
如果同一消费者组内,所订阅的消息是不相同的,那么在执行分区分配的时
候,就不是完全的轮询分配,有可能会导致分区分配的不均匀。如果某个消费
者没有订阅消费组内的某个 topic,那么在分配分区的时候,此消费者将不会
分配到这个 topic 的任何分区。
例如:同一消费者组中,有 3 个消费者 C0、C1 和 C2,他们共订阅了 3 个主题:t0、t1 和 t2,这 3 个主题分别有 1、2、3 个分区(即:t0 有 1 个分区
(p0),t1 有 2 个分区(p0、p1),t2 有 3 个分区(p0、p1、p2)),即整个消费者
所订阅的所有分区可以标识为 t0p0、t1p0、t1p1、t2p0、t2p1、t2p2。具体
而言,消费者 C0 订阅的是主题 t0,消费者 C1 订阅的是主题 t0 和 t1,消费者
C2 订阅的是主题 t0、t1 和 t2,最终分区分配结果如下:
消费者 C0
消费 t0p0
消费者 C1
消费 t1p0 分区
消费者 C2
消费 t1p1、t2p0、t2p1、t2p2 分区
RoundRobin 轮询分区的弊端
从如上实例,可以看到 RoundRobin 策略也并不是十分完美,这样分配其实并
不是最优解,因为完全可以将分区 t1p1 分配给消费者 C1。
所以,如果想要使用 RoundRobin 轮询分区策略,必须满足如下两个条件:
l 每个消费者订阅的主题,必须是相同的。
l 每个主题的消费者实例都是相同的。(即:上面的第一种情况,才优先使用
RoundRobin 轮询分区策略)。
什么时候触发分区分配策略
当出现以下几种情况时,Kafka 会进行一次分区分配操作,即 Kafka 消费者端的 Rebalance 操作
l 同一个 consumer 消费者组 group.id 中,新增了消费者进来,会执行
Rebalance 操作。
l 消费者离开当期所属的 consumer group 组。比如主动停机或者宕机。
l 分区数量发生变化时(即 topic 的分区数量发生变化时)。
l 消费者主动取消订阅。
Kafka 消费端的 Rebalance 机制,规定了一个 Consumer group 下的所有
consumer 如何达成一致来分配订阅 topic 的每一个分区。而具体如何执行
分区策略,就是上面提到的 Range 范围分区 和 RoundRobin 轮询分区 两
种内置的分区策略。
Kafka 对于分区分配策略这块,也提供了可插拔式的实现方式,除了上面两种
分区分配策略外,我们也可以创建满足自己使用的分区分配策略,即:自定义
分区策略。
面经资料来自网络
以搞定。
 
 
腾讯面经
1. 看你项目介绍中大量使用了 Redis,那能不能介绍下 Redis 的主从同步机
制呢?
关于这道题,因为我在之前的文章也分析过 Redis 主从同步的机制,所以我从 完整重同
步 和 部分重同步 两个阶段去分析的,结果也得到了面试官的认可。详细的完整重同步和
部分重同步机制原理是什么样的,在这里就不展开介绍了。
Redis 主从复制
和 Mysql 主从复制的原因一样,Redis 虽然读取写入的速度都特别快,但是也会产生读压
力特别大的情况。为了分担读压力,Redis 支持主从复制,Redis 的主从结构可以采用一
主多从或者级联结构,Redis 主从复制可以根据是否是全量分为全量同步和增量同步。
全量同步Redis 全量复制一般发生在 Slave 初始化阶段,这时 Slave 需要将 Master 上的所有数据
都复制一份。具体步骤如下:
l 从服务器连接主服务器,发送 SYNC 命令;
l 主服务器接收到 SYNC 命名后,开始执行 BGSAVE 命令生成 RDB 文件并使用缓冲区
记录此后执行的所有写命令;
l 主服务器 BGSAVE 执行完后,向所有从服务器发送快照文件,并在发送期间继续记录
被执行的写命令;
l 从服务器收到快照文件后丢弃所有旧数据,载入收到的快照;
l 主服务器快照发送完毕后开始向从服务器发送缓冲区中的写命令;
l 从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命
令;完成上面几个步骤后就完成了从服务器数据初始化的所有操作,从服务器此时可以接收来
自用户的读请求。
增量同步
Redis 增量复制是指 Slave 初始化后开始正常工作时主服务器发生的写操作同步到从服务
器的过程。
增量复制的过程主要是主服务器每执行一个写命令就会向从服务器发送相同的写命令,从
服务器接收并执行收到的写命令。
Redis 主从同步策略
主从刚刚连接的时候,进行全量同步;全同步结束后,进行增量同步。当然,如果有需
要,slave 在任何时候都可以发起全量同步。redis 策略是,无论如何,首先会尝试进行
增量同步,如不成功,要求从机进行全量同步
2. 你们项目中 Redis 的内存使用和过期数据是怎么做的?
这是两道题,先来说说内存是怎么设计的,首先我们是按照业务维度去评估资源内存的使
用量和 QPS 两个维度去评估 Redis 该部署多少资源,然后提到了业务中 Redis 的部署
方式及原因。然后在聊到过期数据的剔除策略,这些在之前的文章也有介绍过,附上链接
朋友们自行查看吧。缓存过期剔除策略
1.内存使用:(增加内存;使用内存淘汰策略;Redis 集群。)  看到
https://blog.csdn.net/u014590757/article/details/797880762.过期数据:Redis 中有个设置时间过期的功能。
https://www.cnblogs.com/xuliangxing/p/7151812.html
3. 看你在实际项目中使用 Streaming 做了一些实时推荐的项目,能介绍下
吗?
我们的部分实时推荐项目使用的是 Steaming,其通过对 Kafka 的 Consumer 进行了二
次开发封装,屏蔽了 Kafka 不同版本对于业务的影响,同时也可以用 Steaming 去对接
不同的数据源,比如现在也支持 xx 数据源的消费;
SparkStreaming 的 Receiver 方式和直连 direct 方式:
https://www.cnblogs.com/hdfs/p/9971761.html
4. 既然使用了 Kafka,你知道为什么 Kafka 那么快吗?
这道题之前在 Kafka 常见面试题中有提到过,这里需要补充一点是,Kafka 的“零拷
贝”机制需要朋友在深入研究下,在之前的文章里面没有深入解释过这个点,剩余的其他
方面附上链接朋友们自行查看吧:Kafka 为什么那么快
5. 使用 Kafka 有遇到过重复消费的情况吗?你们是怎么解决的?
有遇到过,这里补充一点,因为业务形态所决定消息重复消费产生的影响不是特别严重,
所以在一定程度上可以暂时接受,后续通过一些手段去解决了,解决办法之前介绍过如何
处理,懒得在这里继续重复了,接看链接吧:Kafka 重复消费怎么办6. 关于项目咱们先聊这么多,出个题吧,怎么实现一个阻塞队列?
消费线程等到非空了消费,生产线程等到非满了生产;阻塞队列(BlockingQueue)是一
个支持两个附加操作的队列。这两个附加的操作是:在队列为空时,获取元素的线程会等
待队列变为非空。当队列满时,存储元素的线程会等待队列可用。阻塞队列常用于生产者
和消费者的场景,生产者是往队列里添加元素的线程,消费者是从队列里拿元素的线程。
阻塞队列就是生产者存放元素的容器,而消费者也只从容器里拿元素。
7. MySQL 熟悉吗?MySQL 事务是什么?
ACID 准备下,时间不多了,直接略过,准备面试的朋友们记得准备一下哈。简单聊了下
读未提交、读已提交、重复读、序列化几种情况。需要额外再准备下业务中使用的事务隔
离级别是怎么用的(我在项目中使用的 MySQL 不多,面试官也没有多问,主要是一个小
时的面试时间快到了,哈哈哈)
Transaction
l 事务:一个最小的不可再分的工作单元;通常一个事务对应一个完整的业务(例如银行
账户转账业务,该业务就是一个最小的工作单元)
l 一个完整的业务需要批量的 DML(insert、update、delete)语句共同联合完成
l 事务只和 DML 语句有关,或者说 DML 语句才有事务。这个和业务逻辑有关,业务逻
辑不同,DML 语句的个数不同。
https://blog.csdn.net/w_linux/article/details/796660868. 知道 MySQL 的 MVCC 机制吗?
平时基本不用 MySQL,这个没答出来,之后了解了下 InnoDB 大概是通过 undo log
和版本号机制来实现的(怪我没有充分准备就面试了,哈哈,自己活该)
多版本控制(Multiversion Concurrency Control)
: 指的是一种提高并发的技术。最早
的数据库系统,只有读读之间可以并发,读写,写读,写写都要阻塞。引入多版本之后,
只有写写之间相互阻塞,其他三种操作都可以并行,这样大幅度提高了 InnoDB 的并发
度。在内部实现中,InnoDB 通过 undo log 保存每条数据的多个版本,并且能够找回数
据历史版本提供给用户读,每个事务读到的数据版本可能是不一样的。在同一个事务中,
用户只能看到该事务创建快照之前已经提交的修改和该事务本身做的修改。
9. JVM 的垃圾回收机制了解吗?
标记-清楚算法、复制算法、标记-压缩算法、分代收集算法的实现原理。
一、 技术背景
二、 哪些内存需要回收?
2.1 引用计数算法
2.1.1 算法分析
2.1.2 优缺点
2.1.3 是不是很无趣,来段代码压压惊
2.2 可达性分析算法
2.3 Java 中的引用你了解多少2.4 对象死亡(被回收)前的最后一次挣扎
2.5 方法区如何判断是否需要回收
三、常用的垃圾收集算法
3.1 标记-清除算法
3.2 复制算法
3.3 标记-整理算法
3.4 分代收集算法
3.4.1 年轻代(Young Generation)的回收算法
3.4.2 年老代(Old Generation)的回收算法
3.4.3 持久代(Permanent Generation)的回收算法
四、常见的垃圾收集器
五、GC 是什么时候触发的(面试最常见的问题之一)
5.1 Scavenge GC
5.2 Full GC
https://www.cnblogs.com/1024Community/p/honery.html
10. 项目中用的是 CMS 垃圾回收器吗?为什么要分为四个阶段?
初始标记,并发标记,重新标记,并发清理四阶段,系统要求快速响应低延迟,对于多核
 
 
 
美团面经
1、Spring:有没有用过 Spring,Spring IOC、AOP 机制与实现,Spring
MVC
其实我挺不想被问到 Spring 的细节的,框架这些我都没有复习不太记得了。所以我对面
试官说 Spring 里面的一些比较重要的机制我理解的还不错,然后我用一个实际的例子把
我对 IOC、AOP 理解讲了一下,他听了说对,理解的不错(难得遇到一个边面试边能给反
馈的面试官,好开心)。
Spring MVC 其实我用过,我就对面试官讲了我的项目中用到的 Servlet,jsp 和
javabean 实现的 MVC,以及 MVC 各个模块职责以及每个模块是怎么联系到一起的,最
后我补充了一句我想 SpringMVC 的思想其实跟这个是一样的(他说对的,嘿嘿有反馈真
好)
2、多线程:怎么实现线程安全,各个实现方法有什么区别,volatile 关键字的
使用,可重入锁的理解,Synchronized 是不是可重入锁
这里我就主要讲了 Synchronized 关键字,还有并发包下面的一些锁,以及各自的优缺点
和区别。volatile 关键字我主要从可见性、原子性和禁止 JVM 指令重排序三个方面讲的,
再讲了一下我在多线程的单例模式 double-check 中用到 volatile 关键字禁止 JVM 指令重
排优化。
3、集合:HashMap 底层实现,怎么实现 HashMap 线程安全我讲了一下 HashMap 底层是数组加单链表实现,Node 内部类,add 的过程,Hash 冲
突解决办法,扩容,三种集合视图。HashMap 线程安全的实现方式主要讲了
HashTable、ConcurrentHashMap 以及 Collections 中的静态方法 SynchronizedMap
可以对 HashMap 进行封装。以及这三种方式的区别,效率表现。
4、JVM 内存管理,GC 算法,HotSpot 里面的垃圾回收器、类加载
JVM 内存主要分为五个区,哪些是线程共享的,哪些是线程独享的,每个区存放什么。
GC 方面:怎么判断哪些对象需要被 GC,GC 的方法,Minor GC 与 Full GC。HotSpot
GC 算法以及 7 种垃圾回收期,主要讲了 CMS 和 G1 收集器。类加载:类加载的过程,
Bootstrap classloader-ExtClassloader-AppClassloader,父类委托机制。
5、进程和线程的区别
从调度、并发性、拥有的资源和系统开销四个方面回答的。
6、HTTP 有没有状态,我说无状态,怎么解决 HTTP 无状态
怎么解决 HTTP 无状态其实就是怎么进行会话跟踪,有四种方法:URL 重写、隐藏表单
域、Cookie、Session。
7、Java IO,NIO,Java 中有没有实现异步 IO
Java IO 实现的是同步阻塞,它是怎么实现同步阻塞的。我拿了 read()方法举例来讲的。
NIO 实现的是同步非阻塞,我详细讲了一下 Selector 中的 select()方法轮询说明它是如何
实现多路复用 IO 的。然后对比了一下他们的效率。面试官可能看我对这一块比较了解,又继续问我 Java 中有没有实现异步 IO,我感觉好像没有,但面试官说有,让我想想,其
实这里我并不清楚啦,所以我就对面试官讲了一下我对 Unix 中异步 IO 模型的理解,然后
说至于 Java 里面有没有我真的不太清楚。(他居然笑了!说你理解是对的,Java 里面有没
有不重要!哈哈)
8、前端会不会,Ajax 是什么,Ajax 实现原理
前端我只是会用一些 js 而已,用过 jquery 框架,问我 Ajax 全称是啥,我猜是异步的 js 和
xml。Ajax 实现原理其实我也不懂,我就只简单讲了一下它通过 XMLHttpRequest 对象
进行异步查询,Ajax 引擎在客户端运行,减少了服务器工作量。
9、让我设计一个线程池
因为我简历中有写到我对多线程、并发这一块理解比较好。所以他老问这方面的题。这个
问题因为我之前看过 ThreadPoolExecutor 的源代码,所以我就仿照那个类的设计思路来
想的,详细讲了一下核心池、创建线程可以用工厂方法模式来进行设计、线程池状态、阻
塞队列、拒绝策略这几个方面。设计的还算比较周全。
10、讲几个设计模式,哪些地方用到了,为什么要用
单例模,jdk 中的 getRuntime();工厂方法模式,ThreadPoolExcutor 用到
ThreadFactory;观察者模式:java.util 包下面的 Observable 和 Observer。最后主要讲
了一下工厂方法模式的使用场景。
面经资料来自网络

4 年经验裸辞 2 个月,40 场面试一路的心态变化及经验总结

Hello,大家好,你们的猫哥又上线了,有段时间没更新文章了,因为最近在跳槽,所以一直没空写文章,所以耽误了。

先说明一下,猫哥是做前端的,一直在广州工作,所以面试的公司基本都是广州的大中小厂,也面试了 3 个深圳的大厂。

猫哥是 8 月下旬裸辞的,到 11 月 3 号才入职新公司,过程经历了 2 个月,9 月初开始就一直在面试大中小厂,每一轮算一场的话,面试了差不多 40 场,每个岗位走完全部流程大概要三到四场面试,自我介绍都说吐了。

方向

猫哥已经工作 4 年了,再过 3 年就 30 了,30 以后可能很少在一线写代码了吧,一般都到前端 leader 或者管理层了吧。

所以这次找工作主要看公司发展是不是在高速发展中、能不能有比较多的机会、职位的晋升、所做的业务是不是核心业务。所幸,这次找的公司就是这个方向的,最后定的级别还比较高,待遇给得也很不错。

往往是 求上得中,求中得下,求下。。。所以一开始的目标定高一些,虽然结果得不到自己最想要的,结果也不会差到哪里去,跟找女朋友是一样的。。。

准备

如果把自己看成一个产品,那么简历就是说明书。

先是准备好简历,写简历看似简单,想写好实则不容易。一份好的简历能帮你在一堆简历中脱颖而出。

这次投递过的公司,只要符合岗位要求的,基本都有面试机会,我的简历写得还是可以的,如果你不知道简历怎么写,可以看看这篇文章:10 个 GitHub 上最火的程序员简历项目!

猫哥裸辞后,复习了十几天,刷了些面试题,就开始面试了,也没有刷算法题,所以大厂面试的算法题都是靠临时发挥的,只通过了接近一半半吧,难的算法题基本都挂了,比如字节和微信的面试就跪在算法题考核了,知道自己算法不太行,所以都只面了一个部门,不过就算了。

正确的思路应该是:提前 2 - 3 个月开始复习面试的知识点的,提前 5 - 6  个月左右刷算法题的,这次只复习了十几天,比较仓促、准备不够充分啊,唉。

面试了那么多场,大概总结了一下:4 年经验的技术面试中,基础知识占 30%、技术深度及原理占 20%、项目占 30%、算法及编辑题占 15%、技术广度占 5%

我个人觉得突击刷面试题还是很有效果的,但平时的积累能让突击的效果更明显,因为好多知识点是相通的。

项目

对于多年工作经验的人来说,项目就比较重要了,所以要着重准备项目,理清项目中用到的技术、遇到的难点有哪些、又是怎么解决的、对项目做过哪些性能优化、做过的亮点有哪些 等等。

几乎每一场面试,面试官都会问到其中的问题,然后面试官追加的问题,只能自由发挥了。虽然项目中一些特别细节的问题我也不太清楚了,但一般面试官只听一遍你的项目,也不会问到那么细节,一般都不会有什么问题。

所以,着重准备 项目中遇到的难点有哪些、又是怎么解决的、对项目做过哪些性能优化、做过的亮点有哪些、把一个项目的关键模块回顾并吃透,特别有用,而且还占很大一个比重,而且还能由你自由发挥引导,这不重点准备还准备啥呢?

现在回头看,我发现自己准备项目过程中有一点不足:深度不够,回答的不够深度,所以技术上会给面试官一种技术深度还有一点欠缺的感觉,所以有些公司最终没发 offer。

面试

虽然知道裸辞会很焦虑,但是也是想给自己一点压力,能更专注的学习与复习的,本来也是打算找一个月左右应该能找到想去的公司,但是还是出现了意外,大厂的面试流程又长,流程走完,最快也是 3 周到 1 个月左右,所以最后又把战线拉长到了 10 月份。

9 月份只面试了 15 场左右,有时隔几天才面试一场,10 月份就厉害了,虽然工作日的时间只有 3 周,但是安排的面试最为密集,基本上 25 场左右,平均每天都安排 2 ~ 3 场,有时一天有 4 场的:上午一场、中午两场、晚上还有一场。

因为现在大部分公司的面试都在线上了,也是条件允许。不然我也不可能在一天内面试这么多场。

之所以那么密集是因为到 10 月下旬的时候,想去的大厂的流程都走完了 ,但是还没发 offer,之前就有 2 家大厂是每轮面试都通过了,最后就是不发 offer 的场景,所以比较担心和焦虑。自己也将近失业 2 个月了,所以想投一些不错的中厂来保底,通过面试来知道自己还有哪些知识点还不熟悉的,也是为了麻木自己,为了让自己不那么焦虑。

一天面试 2 - 3 场下来,比上班累太多了,直接累得躺床上,不想动。

我面试的思路是:先面试一些小公司,基本都拿到 offer 了,再去面试一些不想去的大公司,觉得稳了,再面试最想去的公司,当然如果你很牛逼,可以不用按这个思路来。

猫哥就是按上面的思路来的,面试过的小厂都走到了最后一轮,其本都能拿到 offer 才开始面试大厂,有些小厂是给不起想要的薪资的,就没发 offer。

一开始是每场面试我都会记录技术问题的,方便查漏补缺,但是到后期就只记录一些自己回答不好的问题了,因为很多问题我都遇到过了的。

面试到 10 月份的时候,发现那些面试官问的基本都是这些了,很多问题的答案我都说了十几遍,想不记住都难、张口就来那种。

技术问题的回答率从 9 月份的 85% - 90% 左右到 10 月份的 95% 左右,技术面试基本都是通过的了。

所以,多面试也有好处,战线拉得长一点,你的失误会越来越少,也会越来越明确自己的目标,不会将就

心态

心态的变化还是很重要的,比如我第一次跳槽的面试,就是还没面多少家,有公司给了 offer 就不想在面了,不断暗示自己这个 offer 也挺好的就去了。

而这次 9 月的大厂面试很多都跪在了第一轮或者第二轮,只收到一个大厂 offer,不是最想去的公司,所以就没去。所以 9 月份的收到的大中小厂的 offer 都被我拒绝了。

9 月过得十分的焦虑,而且 9 月过了中秋,10 月还过了一个国庆,本来想着 10 月前能正常上班了的,然而事情并没有想的那么顺利,所以带着焦虑的心情又渡过了一个国庆,但是仍然相信有好的 offer 在等着自己。

刚过完国庆第二天还发烧了一场,烧到了接近 40 度,而那天是有去现场面试的,因为那天一二轮的面试官都在公司,所以我特意让 HR 安排我去现场面试,加快面试流程,过了一轮直接进入下一轮的,最终也顺利走完了二轮技术面试,虽然最终没有拿到 offer。到 10 月中旬及之后才不断有好消息传来,面试的大中厂都通过了,心态才没那么焦虑。

现在往回看,这次的裸辞还是很冲动吧,爱情、事业双失的两个月,心态时好时坏,注意力都不能很好的集中,时而在崩溃的边缘挣扎,有时还失眠,所以一直在调整心态。

当没有好 offer 时,心里就会想,有一份稳定的工作,在之前公司正常上班多好啊,心态就不会焦虑了。

所以我觉得最重要的就是沉得住气,千万别中途心态崩了影响自己的选择,越到后期越要稳住心态,好的 offer 往往都是在最后的。

如果心态不太稳定的同学,就不建议裸辞去面试了,当然如果心态完全不受影响,裸辞不裸辞无所谓,什么社保断不断那都有别的办法,心态不影响的话甚至裸辞面有更充足的时间准备,裸辞还是不裸辞,得看自己的情况。

还有就是找工作最好在 3 - 4 月份,不要选择 9 - 10 月份,因为 9 - 10 月份有很多假期,有中秋、国庆,选择在那时裸辞找工作是真的不明智,心态会很焦虑、而且如果面试不顺利的话,可能拖到 11 甚至 12 月份,快过年了,那时很少公司招人了,心态可能就更崩溃了。

耐心

很多人可能面了几场之后,就身心俱疲,有公司给了 offer 就去入职了。

因为一场面试还是很累的,要组织语言,要高强度回答一些烧脑的问题,做一两道编辑题或者做一两道算法题,所以相当于近乎一小时都在高强度用脑。面试比上班还累、再加上心理压力,可能会慢慢磨平一个人的意志,影响一个人的心态。

所以 首先要做到心态放平,记住你和公司是双向选择 ,然后把自己的时间拉长,而且我发现面试这个事情也是个玄学,也很看运气,每个面试官侧重的点都是不同的,而且十分看眼缘,如果这个面试官看你不顺眼,或者没有看对眼,你的技术回答得再好也不会让你过,或者特意刁难你,面试官不会让自己不爽的人来做同事的,如果你遇到一个看你很顺眼的面试官真的很幸运。猫哥在某次的第三面终面的时候就遇到了这么一个面试官,一脸很吊、看不起人的样子,让人很不爽,还没开始面试,我就知道难了。。。

其实我觉得面试心路历程中间有一道坎,在面大概一个月的时候有点累。但后面一旦过了这个坎,后面会比较顺利,一方面由于自己复习的越来越好,遇到的很多问题都重复的,已经熟练到可以张嘴就来,所以脑力耗费也在逐渐降低,另一方面就是已经习惯了面试的节奏和气场。

其中一个 Vue 响应式原理,基本每个技术面试官都会问,以至于后面被问的时候,已经熟练到不敢说得太快了,怕被面试官看出来。

所以,一定要渡过中间那到坎,前面咬咬牙坚持过去,后期柳暗花明。

而且,面得越多,失误越少,你真的会发现,面试题已经逃不出之前面试官问你的那些问题了,所以,渐渐的就没有失常发挥,只有超常发挥。

互联网的圈子真的很小,广州的就更小了,面试时,有些公司的人是和我现在的公司的人认识的,有些会问前同事关于我的情况。

所以每一份工作都要好好干,就算离职了,也留下一个好的口碑,不影响下一份工作,甚至对下一份工作有帮助。

尴尬

还让朋友内推和猎头帮我投了一些深圳的公司的,不过只有 3 个面试机会。招聘方那边会觉得你 4 年都在广州工作,在深圳不会待太久的,或者觉得你只是看看机会而已的,不会真的想来深圳,这个就比较难了。

面试虾皮的时候,那个面试官还问了我 3 次相关的问题,为什么离开广州、打算在深圳待多久、真的会来深圳工作吗。。。

裸辞两个月,第二个月还在找到工作时,面试时还会被问为什么还没找到工作。。。

还会一直被问为什么辞职。。。

有些 HR 还一直问之前几次换工作是为啥。。。

跳槽是为什么?钱给少了呗、干得不爽了呗。。。

有些面试官的态度真的很差。。。

有些面试官还不是按你掌握的技术来提问题的,而是按他自己使用的技术来问的。。。

原以为一线大厂的薪资比较高,却发现却和目前的差不多,有的比我现在的还低,涨 20% 都不肯。。。不过这也正常,大厂招人容易,很多人低价也要进大厂,而小厂招人难,所以肯给高价。还就一个原因就是广州中像样的大厂也就那么几家而已,所以非常的内卷。

还发现有的大厂的晋升很恶心人,晋升只能通过 leader 来点名才能参加晋升。。。这不是会养成下级巴结 leader、或者 leader 拉帮结派的现在吗。。。

还发现很多大厂的工作环境比不上之前公司的,毕竟之前是在广州 CBD,甲等写字楼、一流的工作环境。

最后

总的来说,这次 2 个月的面试过程,还是学到了不少,熟悉了自己原来的项目,体系化的巩固了基础知识、对某项技术的深度也加深了,以前没了解过的技术也在次被迫了解到了,也很大的锻炼了自己的心志。

希望大家也能清晰自己的目标,找到合适满意的工作,不将就。

这次换工作还得感谢帮我内推指点的朋友:亮哥、恩杰哥、荣哥、鹏哥、七淅哥、轻风哥、龙哥,谢谢各位大佬了,给我提供了很大的帮助,还要谢谢一些猎头也给我内推了好的岗位。

还想写一篇《4 年经验裸辞 2 个月,面试大中小厂共 40 场,高频出现的 100 道前端试题及答案》,如果朋友们想看的,请给本文点个赞哦,我看看有多少人想看,我再决定要不要写。

如果你也有面试的问题或者困惑,可以找我聊聊,猫哥的微信:CB834301747。

以上是关于各场面试经验的主要内容,如果未能解决你的问题,请参考以下文章

4 年经验裸辞 2 个月,40 场面试一路的心态变化及经验总结

40+场面试,100%通过率,我想分享的14条经验

40+场面试,100%通过率,我想分享的14条经验

下次一定会成,Android面试血泪教训(九场面试的经验与得失)

下次一定会成,Android面试血泪教训(九场面试的经验与得失)

百场面试