扫码关注公众号:芋道源码

发送: 百事可乐
获取永久解锁本站全部文章的链接

《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 占小狼的博客 「狼哥很猥琐」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注微信公众号:【芋道源码】有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
  4. 新的源码解析文章实时收到通知。每周更新一篇左右
  5. 认真的源码交流微信群。

马老师说过,员工的离职原因很多,只有两点最真实:

1、钱,没给到位

2、心,受委屈了

以下是占小狼的一些实战面试经验分享,希望能帮助你们顺利拿到理想Offer!

厮大牛逼

项目经验

面试官在一开始会让你进行自我介绍,主要是想让你介绍一下自己做过的一些项目,看看你对这些项目的了解程度。

因为很多人简历上写的项目并非都是从头到尾都参与的,有些只是参与并实现了其中的一些模块而已,或是接手维护别人的项目,所以在你简历上所写的和面试过程中所说的项目经验,你自己必须能够了解来龙去脉。之后,面试官也会根据你的项目描述,对项目中的实现原理,或为什么要这样实现进行提问,如果你木讷住,不知如何作答,只会大大降低面试分。

面试场景:

面试官:(拿着简历)讲讲你最近做的这个项目

我: &……%¥#*&¥@%¥!,说了一大通

PS:不知道面试官听进去多少,面试官会挑他熟知的知识点进行提问。

面试官:你说这个项目中用到了netty,能大概讲讲netty的线程模型么?

我:(幸好我看过netty的源码)netty通过Reactor模型基于多路复用器接收并处理用户请求(能讲就多讲一点),内部实现了两个线程池,boss线程池和work线程池,其中boss线程池的线程负责处理请求的accept事件,当接收到accept事件的请求时,把对应的socket封装到一个NioSocketChannel中,并交给work线程池,其中work线程池负责请求的read和write事件。

PS:通过口述加画图的方式,把请求的执行过程大概描述了一遍,时间有限,也不可能把所有的细节都说完,挑重点讲,挑记忆深刻的讲。

面试官:嗯,理解的还挺深入的…那你在做这个项目时有没有遇到什么困难,或者是觉得有挑战的地方?

我:因为之前确实碰到了这个问题,当时做这个项目时,对netty的不过熟悉,把请求的业务逻辑放在work线程池的线程中进行处理,进行压测的时候,发现qps总是上不去,后来看了源码之后才发现,由于业务逻辑的处理比较耗时,完全占用了work线程池的资源,导致新的请求一直处于等待状态。

PS:这时面试官想让你自己出题自己回答了,所以一定要回答,不回答就突显不出你这个项目了,要是这个问题没有准备过,只能临时发挥了,当然我就是属于临时发挥的

面试官:那最后是如何解决的?

我:最后把处理业务的逻辑封装成一个task提交给一个新建的业务线程池中执行,执行完之后由work线程池执行请求的write事件。

面试官:好的,你知道nio中selector可能触发bug么?

我:嗯,对的,selector的select方法,因为底层的epoll函数可能会发生空转,从而导致cpu100%。

面试官:那如何解决该问题?

我:这个问题在netty已经解决了,通过&^%&$^(把netty的解决方案说一遍)

面试官:嗯,对了,你们这个项目有给自己定指标么?

我:有的……把自己项目的指标说了一通,如何进行AB实验,如何迭代优化指标

面试官:嗯,好的 ,项目的问题先到这里,我们来考察一下java的基本点吧。>

如上只是本人所做的一个项目,当然了,具体项目具体分析,也不是每个面试官问的点都一样。如果面试官不懂netty,自然会挑别的问题进行提问,不过尽量尝试着把问题往自己熟悉的方向去靠。

面试知识点

1、线程池

线程池的实现原理,这个知识点真的很重要,几乎每次面试都会被问到,一般的提问方式有如下几种:

  • 1、“讲讲线程池的实现原理”
  • 2、“线程池中的coreNum和maxNum有什么不同”
  • 3、“在不同的业务场景中,线程池参数如何设置”

面试场景:

面试官:平时线程池用的多么?

我:嗯,我的*项目中就用到了。

面试官:那好,你讲讲线程池的实现原理

我:能给我笔和纸么,我画图分析给你看看,……假设初始化一个线程池,核心线程数是5,最大线程数是……

面试官:嗯,好的,你继续…

我:在纸上画了正方形,这个代表一个线程池,初始化的时候,里面是没有线程的

面试官:嗯,好的,你继续…

我:又画了一个细长的长方形,这个代表阻塞队列,一开始里面也是没有任务的。当来了一个任务时,在正方形中画了一个小圆圈,代表初始化了一个线程,如果再来一个任务,就再画一个圆圈,表示再初始化了一个线程,连续画了5个圆圈之后,如果第6个任务过来了…

面试官:嗯,好的,你继续…

我:这时会把第6个任务放到阻塞队列中..

面试官:嗯,然后呢?

我:现在线程池中不是有5个线程了么,如果其中一个线程空闲了,就会从阻塞队列中获取第6个任务,进行执行..

面试官:嗯,对的,那如果任务产生的速度比消费的速度快呢?

我:如果线程池的5个线程都在running状态,那么任务就先保存在阻塞队列中

面试官:如果队列满了,怎么办?

我:如果队列满了,我们不是设置了最大线程数是10么,而线程池中只有5个线程,这时会新建一个线程去执行不能保存到阻塞队列的任务,然后我又在正方形中画了5个圆圈。

面试官:那如果线程池中的线程数达到10个了,阻塞队列也满了,怎么办?

我:这种情况通过自定义reject函数去处理这里任务了,舒了一口去,以为问完了…

面试官:好的,那如果运行一段时间之后,阻塞队列中的任务也执行完了,线程池中的线程会怎么样?

我:…这个好像超过核心线程数的线程会在空闲一段时间内自动回收…因为有点不记得这个逻辑了,回答的有点虚…

面试官:好的,那这种情况在什么场景下会发生?

我:这个…那个…我好像没有遇到过这样的情况……

面试官:嗯,好的,你回去之后再好好想想。

我:……..

PS:面试真的会紧张,导致很多明明知道的东西却全忘记了。所以一定要放松放松。而且有蛮多面试官其实会很耐心,会引导你,但也会沿着你的思路一直细问下去,所以一定要确保自己思维逻辑清晰。

我居然忘记了“秒杀”这个场景!

2、锁的实现

在关于锁的面试过程中,一般主要问Synchronized和ReentrantLock的实现原理,更有甚者会问读写锁。

面试场景

面试官:都了解Java中的什么锁?

我:比如Synchronized和ReentrantLock…读写锁用的不多,就没研究了。

PS:我就怕被问读写锁,因为一直没去看。所以,对一些自己不了解的话题,尽量少说一点,也坦白承认自己不会。

面试官:那好,你先说说Synchronized的实现原理吧。

我:嗯,Synchronized是JVM实现的一种锁,其中锁的获取和释放分别是monitorenter和monitorexit指令,该锁在实现上分为了偏向锁、轻量级锁和重量级锁,其中偏向锁在1.6是默认开启的,轻量级锁在多线程竞争的情况下会膨胀成重量级锁,有关锁的数据都保存在对象头中……

面试官:哦,嗯,理解的还挺透彻,那你说说ReentrantLock的实现吧…

我:ReentrantLock是基于AQS实现的

面试官:什么是AQS?

我:在AQS内部会保存一个状态变量state,通过CAS修改该变量的值,修改成功的线程表示获取到该锁,没有修改成功,或者发现状态state已经是加锁状态,则通过一个Waiter对象封装线程,添加到等待队列中,并挂起等待被唤醒……

面试官:能说说CAS的实现原理么?

我:CAS是通过unsafe类的compareAndSwap方法实现的(心里得意的一笑)

面试官:哦,好的,那你知道这个方法的参数的含义的么?

我:这个方法看的时间有点久远了,第一个参数是要修改的对象,第二个参数是对象中要修改变量的偏移量,第三个参数是修改之前的值,第四个参数是预想修改后的值….

面试官:嗯,对的,那你知道操作系统级别是如何实现的么?

我:(我去你大爷…)我只记得X86中有一个cmp开头的指令,具体的我忘记了…

面试官:嗯,好,你知道CAS指令有什么缺点么

我:哦,CAS的缺点是存在ABA问题。

面试官:怎么讲?

我:就是一个变量V,如果变量V初次读取的时候是A,并且在准备赋值的时候检查到它仍然是A,那能说明它的值没有被其他线程修改过了吗?如果在这段期间它的值曾经被改成了B,然后又改回A,那CAS操作就会误认为它从来没有被修改过。

面试官:那怎么解决?

我:(有完没完了啊…我的心里是崩溃的)针对这种情况,java并发包中提供了一个带有标记的原子引用类”AtomicStampedReference”,它可以通过控制变量值的版本来保证CAS的正确性。

面试官:嗯,好的,这个问题到此为止,我们再看看别的。 我:….我能喝口水么

3、ConcurrentHashMap

当考察数据结构时,面试官一开始会问HashMap的实现原理,当你说出HashMap并非线程安全之后,会让你自己引出ConcurrentHashMap,接着就可能开始如下的对话。

面试场景

面试官:谈谈ConcurrentHashMap实现原理

我:……基于分段锁的……,但是1.8之后改变实现方式了。

面试官:1.8啥方式?

我:……(把1.8的实现原理说了一通,其中提到了红黑树)…

面试官:能讲下红黑树的概念吗?

我:红黑树是一种二叉树,并且是平衡……%……¥……,

面试官:能讲下红黑树的……

我:打住,别问了,红黑树我只知道他是二叉树,比其他树多一个属性,其他的我都不知道。 面试官:好的,那换个,你知道它的size方法是如何实现的么?

我:size方法?是想要得到Map中的元素个数么?

面试官:对的….

我:我记得好像size方法返回是不准确的,平时也不会用到这个方法…

面试官:如果你觉得size方法返回值不准确,那如果让你自己实现,你觉得应该怎么实现呢?

我:(两眼一黑)等等,让我想想…..应该可以用AtomicInteger变量进行记录…嗯,对的,每次插入或删除的时候,操作这个变量,我得意的一笑…

面试官:哦,是么,那如果我觉得这个AtomicInteger这个变量性能不好,还能再优化么?

我:懵逼脸…(当时居然把volitile变量给忘记了)…好像没有了,我想不出来了…

面试官:哦,那回头你再看看源码吧,jdk中已经实现了…

我:哦,是么….

面试官:那今天的面试到此结束,我们后面会通知你。

我:……(结束专业用语)

文章目录
  1. 1. 项目经验
  2. 2. 面试知识点
    1. 2.1. 1、线程池
    2. 2.2. 2、锁的实现
    3. 2.3. 3、ConcurrentHashMap