背景是公司需要急招一名高级开发,我记录了一个比较典型小伙伴的面试问答,先看下这位应聘者的简历以及我在面试中提问的技术点(由于篇幅问题,仅抽取技能部分)。
↑ 简历
在还没开始面试前,简历的问题挺明显的:
从技能部分可以看出中间件描述稍微有点少,且技能描述比较模糊,其次关键性的技术没有描述(第三项),第六项需要猜测,不能清晰感知到他会的中间件是什么只能靠面试中来问(很容易栽倒坑里)。
(偷偷问一句,你们的简历是不是也是这样写的?如果是的话可以在下方留言哦!)
面试岗位需求:
面试知识点剧透:
设计模式,Redis,JVM,场景题
正文
省略掉没有任何内容的自我介绍和互相的礼性问候 个人擅长点在设计模式 redis 以及 netty
设计模式
我:
在刚刚的自我介绍中我了解到了你的一定情况,我们来谈一些技术性的问题吧! 从你的开发技能中又描述你对常用的设计模式有深入的了解,能说说你用到的一些设计模式和其对应的业务场景吧,举两个例子即可。
答:
设计模式总共有 23 种,总体来说可以分为三大类:创建型模式( Creational Patterns )、结构型模式( Structural Patterns )和行为型模式( Behavioral Patterns )
我用的最多的是以下三种:简单工厂模 ,单例模式,
简单工厂模式
其中简单工厂模式又叫静态工厂方法模式,其实就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建。比如,一台咖啡机就可以理解为一个工厂模式,你只需要按下想喝的咖啡品类的按钮(摩卡或拿铁),它就会给你生产一杯相应的咖啡,你不需要管它内部的具体实现,只要告诉它你的需求即可。
优点:
工厂类含有必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的责任,而仅仅“消费”产品;简单工厂模式通过这种做法实现了对责任的分割,它提供了专门的工厂类用于创建对象;
客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可,对于一些复杂的类名,通过简单工厂模式可以减少使用者的记忆量;
通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。
缺点:
不易拓展,一旦添加新的产品类型,就不得不修改工厂的创建逻辑;
产品类型较多时,工厂的创建逻辑可能过于复杂,一旦出错可能造成所有产品的创建失败,不利于系统的维护。
单例模式
单例模式则是一种常用的软件设计模式,在应用这个模式时,单例对象的类必须保证只有一个实例存在,整个系统只能使用一个对象实例。
优点:不会频繁地创建和销毁对象,浪费系统资源。
使用场景:IO 、数据库连接、Redis 连接等。
装饰器模式
装饰器模式是指动态地给一个对象增加一些额外的功能,同时又不改变其结构。
优点:装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
装饰器模式的关键:装饰器中使用了被装饰的对象。
比如,创建一个对象“laowang”,给对象添加不同的装饰,穿上夹克、戴上帽子......,这个执行过程就是装饰者模式,
我常用的大概就是这三种。
PS:从这一部分可以看出确实设计模式比较扎实所有我换了一个知识点来问。
JVM
我:
JVM、Dalvik、ART的区别?
答:
首先要明白什么是Dalvik:
Dalvik是Google公司自己设计用于Android平台的Java虚拟机。它可以支持已转换为.dex(即Dalvik Executable)格式的Java应用程序的运行,.dex格式是专为Dalvik应用设计的一种压缩格式,适合内存和处理器速度有限的系统。Dalvik经过优化,允许在有限的内存中同时运行多个虚拟机的实例,并且每一个Dalvik应用作为独立的Linux进程执行。独立的进程可以防止在虚拟机崩溃的时候所有程序都被关闭。
什么是ART:
ART代表AndroidRuntime,Dalvik是依靠一个Just-In-Time(JIT)编译器去解释字节码,运行时编译后的应用代码都需要通过一个解释器在用户的设备上运行,这一机制并不高效,但让应用能更容易在不同硬件和架构上运行。
ART则完全改变了这种做法,在应用安装的时候就预编译字节码到机器语言,这一机制叫Ahead-Of-Time(AOT)预编译。在移除解释代码这一过程后,应用程序执行将更有效率,启动更快。
1. Dalvik与JVM的区别
(1)Dalvik指令集是基于寄存器的架构,执行特有的文件格式——dex字节码(适合内存和处理器速度有限的系统)。而JVM是基于栈的。相对于基于栈的JVM而言,基于寄存器的Dalvik VM实现虽然牺牲了一些平台无关性,但是它在代码的执行效率上要更胜一筹。
(2)每一个Android 的App是独立跑在一个VM中的。因此一个App crash只会影响到自身的VM,不会影响到其他。Dalvik经过优化,允许在有限的内存中同时运行多个虚拟机的实例,并且每一个 Dalvik应用作为一个独立的Linux进程执行。
2. Dalvik与ART的区别
(1)在Dalvik下,应用每次运行都需要通过即时编译器(JIT)将字节码转换为机器码,即每次都要编译加运行,这虽然会使安装过程比较快,但是会拖慢应用的运行效率。而在ART 环境中,应用在第一次安装的时候,字节码就会预编译(AOT)成机器码,这样的话,虽然设备和应用的首次启动(安装慢了)会变慢,但是以后每次启动执行的时候,都可以直接运行,因此运行效率会提高。
(2)ART占用空间比Dalvik大(原生代码占用的存储空间更大,字节码变为机器码之后,可能会增加10%-20%),这也是著名的“空间换时间大法"。
(4)预编译也可以明显改善电池续航,因为应用程序每次运行时不用重复编译了,从而减少了 CPU 的使用频率,降低了能耗。
Redis
我:Redis 有了解过么?
答:有的
我:Redis是单线程的吗?
答:
Redis是单线程的!
Redis 核心就是 如果我的数据全都在内存里,我单线程的去操作 就是效率最高的,为什么呢,因为多线程的本质就是 CPU 模拟出来多个线程的情况,这种模拟出来的情况就有一个代价,就是上下文的切换,对于一个内存的系统来说,它没有上下文的切换就是效率最高的。Redis 用 单个CPU 绑定一块内存的数据,然后针对这块内存的数据进行多次读写的时候,都是在一个CPU上完成的,所以它是单线程处理这个事。在内存的情况下,这个方案就是最佳方案。
在6.0之后是多线程的 但是最终的底层还是单线程的。
我:
在redis底层数据扩容 rehash 那么能简单描述一下吗?
答:
redis字典(hash表)当数据越来越多的时候,就会发生扩容,也就是rehash
对比:java中的hashmap,当数据数量达到阈值的时候(0.75),就会发生rehash,hash表长度变为原来的二倍,将原hash表数据全部重新计算hash地址,重新分配位置,达到rehash目的
redis中的hash表采用的是渐进式hash的方式:
在扩容和收缩的时候,如果哈希字典中有很多元素,一次性将这些键全部rehash到ht[1]的话,可能会导致服务器在一段时间内停止服务。所以,采用渐进式rehash的方式,详细步骤如下:
为ht[1]分配空间,让字典同时持有ht[0]和ht[1]两个哈希表
将rehashindex的值设置为0,表示rehash工作正式开始
在rehash期间,每次对字典执行增删改查操作是,程序除了执行指定的操作以外,还会顺带将ht[0]哈希表在rehashindex索引上的所有键值对rehash到ht[1],当rehash工作完成以后,rehashindex的值+1
随着字典操作的不断执行,最终会在某一时间段上ht[0]的所有键值对都会被rehash到ht[1],这时将rehashindex的值设置为-1,表示rehash操作结束 。
渐进式rehash采用的是一种分而治之的方式,将rehash的操作分摊在每一个的访问中,避免集中式rehash而带来的庞大计算量。
需要注意的是在渐进式rehash的过程,如果有增删改查操作时,如果index大于rehashindex,访问ht[0],否则访问ht[1]。
场景题
我:在这里我问一个业务相关的场景:如何把一个文件快速下发到 100w 个服务器
答:采用p2p网络形式 比如树状形式,网状形式 单个节点既可以从其他节点接收服务又可以向其他节点提供服务。
对于树状传递,在100W台服务器这种量级上,可能存在两个问题:
如果树上的某一个节点坏掉了,那么从这个节点往下的所有服务器全部宕机。
如果树中的某条路径,传递时间太长了(网络中,两个节点间的传递速度受很多因素的影响,可能相差成百上千倍),使得传递效率退化。
改进:100W台服务器相当于有100W个节点的连通图。那么我们可以在图里生成多颗不同的生成树,在进行数据下发时,同时按照多颗不同的树去传递数据。这样就可以避免某个中间节点宕机,影响到后续的节点。同时这种传递方法实际上是一种依据时间的广度优先遍历,可以避免某条路径过长造成的效率低下。
结语
在这里我仅仅抽取了几个经典的几个问题进行提问,面试者的作答也是很标准的,但是简历确实是一个问题点,很容易在前期的简历筛选中被剔除掉 ,明明有很强的能力,结果在第一步就被筛选掉了,如果不是面试很难看出有这么强的能力,那么大家的简历是怎么写的?对比这位面试的老兄,你们差别在哪?
除开这位老兄的例子,我还为每位粉丝准备了一点见面礼,如果你是最近打算跳槽换工作或者正在准备学习更高阶技术点的,你应该能用得上:
- Java架构师学习路线图(更高阶的大佬小弟就不在这献丑了)
- 模块化学习资源(Java并发编程、分布式缓存的原理及应用、ZooKeeper原理及应用、Netty网络编程原理及应用、Kafka原理及应用、常见的23种经典设计模式、Spring原理及应用、数据结构与算法……)
- 2022年大厂面试高频知识点整理
资料持续更新中,目前全部都是免费送给大家,如果有需要,尽管拿走,添加我助手领取,备注“CSDN码农”