32个java面试必考点
1. 32个java面试必考点
1.1. 开篇,张雷介绍,新浪微博技术专家
专注于高可用架构、微服务治理、中间件开发等方向,Motan开源框架技术负责人。
2013年加入新浪微博,作为核心技术成员参与微博服务化、混合云等多个重点项目,目前主要负责weibo mesh项目的规划设计与推进。同时作为新浪微博平台的技术评审官,也负责新员工的转正评审工作,对技术人才的选拔及考核颇有心得。
曾在ArchSummit、WOT、GIAC等顶级会议上进行过高可用架构、微服务实践等方面的分享
2018年有很多工程师向拉勾咨询,提出了他们对工作、求职的诸多困惑:
* 面试前通宵刷题、全网搜索面经,收效甚微;
* 局限于常用技术,对于形成架构思维和体系化梳理知识点还有所欠缺;
* 平时工作能力不错,和领导汇报时却不得要领,不受器重;
补齐能力短板,还能学会如何更好的面向上级、团队展现自己的优势。用于面试前的查漏补缺、职业规划和晋升评审,都有一定参考价值。
- 一线技术老兵
- 微服务技术专家
- 开源Motan负责人
- 微博平台委员会
1.2. 基础模块
1.2.1. 技术岗位与面试流程
1.2.1.1. 简历怎么准备:常见问题
- 工作和项目经验描述的不到位
- 不懂如何包装自己的技术特长
- 学历短板放到显眼位置
- 排版错乱
1.2.1.2. 面试管考什么
- 看岗位要求,简历的工作年限,学历,对口经验,逻辑是否清除都可能是坎。
- 不清楚侧重点,岗位要求:行业角度来看社交门户-高并发架构,020综合能力;年限:校招逻辑考察哦,初中级:知识的广度,基础知识应用;高级资深:深入理解基本原理,各种知识综合运用,考察综合能力。
面试管意图:框架的使用场景,解决什么问题,框架特点,有同类型的其他框架;面试管问问题,是想获取相关的更多信息。
1.2.1.3. 如何晋级
- 不断学习:忌东学西学,学习应该
先建立知识体系;先梗概后细节
1.2.1.4. 职业技术人发展路径
- 常见的技术岗位发展路径及bat的晋升要求:能谈谈职业规划码?:在以往的工作中我堆架构设计,技术攻坚处理比较多,也比较有兴趣,因此计划网技术架构岗位高级发展
- 技术面试流程
- 一面一般是同组同事,面一些基础,基础算法,一小时左右
- 二面直属leader(也可能跟一面一起)偏重项目经验,项目架构图,交互流程图,项目改进方案;考察技术深度,算法。一小时左右
- 项目经历,业规划和视野,架构能里技术敏感度,半技术面,部门leader
- 四面 HR ,非技术,个人发展规划,上家离职原因,价值观,薪资待遇;
- 公司级高管面试5面,工作经历,行业看法,公司看法,未来规划,没原则性错误都能通过
-
如何选择高命中率的岗位
-
面试准备
能力-心态-沟通:面试考察点突击
能力:识--工作经历提炼---项目和架构提炼总结--经典框架原理使用场景实现方式学习
根据面试岗位业务针对性学习:比如中间件
心态:搜集面试岗位团队,平均福利等资料;不利的场景下,免压心态
沟通:1.技术特长和优势,避免冷场2不上来提供解题思路3.没听清要跟面试管确认问题4.注意微表情,不皱眉,语速平稳;面试管突然写字说明,我提供的信息有用;如果不写,可能跑题
如果面试管深呼吸不耐烦,可能没get到点--下一步学习思考能力-项目经验-架构
-
面试考察点
硬技能:
1.2.2. 计算机基础
1.2.2.1. 操作系统
- 进程线程的区别:
- 进程是资源分配的最小单位,线程是程序执行的最小单位
- 进程独立数据空间,线程共享数据空间
-
线程调度
调度算法
-
时间片轮转算法(RR):分时系统的一种调度算法。 轮转的基本思想是,将CPU的处理时间划分成一个个的时间片,就绪队列中的进程轮流运行一个时间片。当时间片结束时,就强迫进程让出CPU,该进程进入就 绪队列,等待下一次调度
-
先来先服务调度算法(FCFS|FIFO队列):就是按照各个作业进入系统的自然次序来调度作业。
-
基于优先数调度算法(HPF):每一个作业规定一个表示该作业优先级别的整数
-
均衡调度算法,即多级队列调度算法
基本概念:
作业周转时间(Ti)=完成时间(Tei)-提交时间(Tsi)
作业平均周转时间(T)=周转时间/作业个数
作业带权周转时间(Wi)=周转时间/运行时间
响应比=(等待时间+运行时间)/运行时间
-
最高响应比优先算法(HRN):FCFS可能造成短作业用户不满,SPF可能使得长作业用户不满,于是提出HRN,选择响应比最高的作业运行。响应比=1+作业等待时间/作业处理时间。
-
短作业优先调度算法****(SPF): 就是优先调度并处理短作业,所谓短是指作业的运行时间短。
-
-
线程切换的步骤:上下文切换及切换代价
这些操作主要有”保存线程A的执行现场“然后”载入线程B的执行现场”,这个过程称之为“上下文切换(context switch)
- 线程从runnable状态转换为非runnable状态都属于线程发生了上下文切换。
- 上下文切换发生方式:线程上下文切换分为主动式和被动式,主动方式是由线程自己发起的上下文切换
自发式:Object.wait,Thread.sleep,Thread.join,LockSupport.park
非自发式:执行到synchronized,lock,阻塞IO方式,垃圾回收 - 代价:
- 直接代价:保存/恢复上下文的时间,从READY状态中选择一个可以执行的线程的时间(线程调度时间)
- 间接代价:高速缓存加载的时间
- 当线程被切换出去之后,可能需要把缓存中的数据刷新到内存中。
-
进程间通信IPC:
- PIPE:管道方式
- MessageQueue:消息队列是内核地址空间中的内部链表
- 共享内存:进程间数据共享,它是在多个进程间对内存段进行映射的方式实现内存共享的。这是最快的IPC方式。
- UnixSocket:进程间数据交换,socket通信
- Signal信号机制是UNIX系统中最为古老的进程之间的通信机制。它用于在一个或多个进程之间传递异步信号
- Semaphore:信号量是一种计数器,用来控制对多个进程共享的资源所进行的访问。它们常常被用作一个锁机制
-
协程
进程切换在用户态调度,切换代价低: CPU划分出两个权限等级 -- 用户态和内核态。内核态:cpu可以访问内存的所有数据,包括外围设备,例如硬盘,网卡,cpu也可以将自己从一个程序切换到另一个程序。
用户态:只能受限的访问内存,且不允许访问外围设备,占用cpu的能力被剥夺,cpu资源可以被其他程序获取。
应用程序请求操作系统以程序的名义执行内核态操作:用户态程序切换到内核态, 但是不能控制在内核态中执行的指令,这种机制叫系统调用, 在CPU中的实现称之为陷阱指令(Trap Instruction)
-
linux命令:
awk,top,netstat,grep,less,tail
-
死锁
死锁的概念:如果一个进程集合中,每个进程都在等待只能由该集合中其他进程才能引发的事件,那么该进程集合就是死锁的:用圆形节点表示进程,方形表示资源,有向图中出现了两个或两个以上进程组成的环路,就会导致死锁的发生。
死锁并不仅仅发生在资源上,资源死锁只是一种。
资源死锁的四个必要条件:
(1)互斥条件。每个资源要么已经分配给了一个进程,要么就是可用的。
(2)占有和等待条件。已经得到了某个资源的进程可以再请求新的资源。
(3)不可抢占条件。已经分配给一个进程的资源不能被抢占,只能由占有它的进程显式地释放。
(4)环路等待条件。死锁发生时,系统中一定有由两个或以上的进程组成的一条环路,该环路中的每个进程都在等待着下一个进程所占有的资源。
-
内存分页管理与Swap
其实内存是三个之和:Mem+buffers/cache+Swap
内存活动基本上可以用3个数字来量化:活动虚拟内存总量,交换(swapping)率和调页(paging)率.其中第一个数字表明内存的总需求量,后两个数字表示那些内存中有多少比例正处在使用之中.目标是减少内存活动或增加内存量,直到调页率保持在一个可以接受的水平上为止.
页面调度通常容易和交换的概念混淆,页面调度是指把一个进程所占内存的空闲部分传输到磁盘上,而交换是指当系统中实际的内存已不够满足新的分配需求时,把整个进程传输到磁盘上,交换活动通常意味着内存不足。
swap -- 草地,就是存放page的硬盘空间。
virtual memory -- 假设刘翔跑n圈就已经是到北京的距离了,可是他们还在原地。虚拟就是不存在的。
page -- 草地上的格,每次只容纳一个人
-
任务队列与CPU Load(7,8,9,10线上排查问题,体现知识深度)
Load Average是 CPU的 Load,它所包含的信息不是 CPU的使用率状况,而是cpu使用队列长度
CPU Utilization 好理解,就是CPU的利用率,75%以上就比较高
Context Switch Rate 。就是Process(Thread)的切换,如果切换过多,会让CPU忙于切换
-
扩展参考:https://www.cnblogs.com/chenyangyao/p/5269622.html
- 内存屏障: (Memory Barrier内存栅栏)用于控制特定条件下的重排序和内存可见性问题;核心等待都到达才继续执行.
- 指令乱序:1. java运行时环境的JIT编译器也会做指令重排序操作,即生成的机器指令与字节码指令顺序不一致。2. 尽可能地避免处理器访问主内存的时间开销,处理器大多会利用缓存(cache)以提高性能,存在一个现象,即缓存中的数据与主内存的数据并不是实时同步的,各CPU(或CPU核心)间缓存的数据也不是实时同步的。这导致在同一个时间点,各CPU所看到同一内存地址的数据的值可能是不一致的。从程序的视角来看,就是在同一个时间点,各个线程所看到的共享变量的值可能是不一致,导致内存可见性问题;看起来就像指令重排序一样.
- 分支预测:条件分支指令通常具有两路后续执行分支。即不采取(not taken)跳转,顺序执行后面紧挨JMP的指令;以及采取(taken)跳转到另一块程序内存去执行那里的指令;分支预测器猜测条件表达式的两路分支中哪一路最可能发生,然后推测执行这一路的指令!
- CPU亲和性(affinity):比如你的电脑安装了一块4核CPU,并且支持且开启了超线程(HT)技术,那么逻辑CPU数量 = 1 × 4 × 2 = 8;CPU affinity 是一种调度属性(scheduler property), 它可以将一个进程"绑定" 到一个或一组CPU上.
- Netfilter与iptables:从用户态的iptables到内核态的Netfilter其交互过程和通信手段.参考:https://blog.csdn.net/yyfaith/article/details/80454584
1.2.2.2. 网络知识(http应用层-tcp|udp传输层-ip网络层-硬件驱动链路层)
- 4/7层模型
- TCP协议:三次握手建连2. 四次挥手断连:高频考点(syn->syn,ack一起发->ack;fin->先发ack再发fin->ack)
- HTTP协议:应用层
1.协议包含method header cookies 2.常见状态吗 - UDP协议:无连接的传输层协议
- QUIC(http3:基于UDP)
tcp知识点及三次握手:洪水攻击了解;
四次挥手断连:
为什么time_wait2倍MSL:1.保证tcp全双工连接正常关闭2.重复的数据断从网络中消失,防止端口重用数据混淆。
存在time_wait:要开启服务器tcp参数加快回收;存在大量close_wait:被动方,一般考虑是代码bug.
1.2.3. Java语言特性和设计模式
1.2.3.1. 设计模式:常用模式实现,及使用场景
三大类型工23种:创建型5种;结构型7种;行为型11种
-
单例模式
1.静态初始化(饿汉式:无论是否使用都会创造这个单例)
2.双重检查(懒汉式:用时创建,所以多线程同时使用实例的并发问题,所以用同步保证只有一个线程创建实例,内存可见性引起并发问题所以用volite修饰单例变量)
3.单例注册表:spring创建单例bean -
工厂模式
Spring如何创建Bean,build模式 -
代理模式
Motan服务的动态代理 -
构造者模式
PB序列化中的Builder -
责任链模式
Netty消息处理的方式 -
适配器模式
适配器模式:将一个类的接口转换成客户希望的另一个接口。适配器模式让那些接口不兼容的类可以一起工作;适配器模式的别名为包装器(Wrapper)模式,它既可以作为类结构型模式,也可以作为对象结构型模式。在适配器模式定义中所提及的接口是指广义的接口,它可以表示一个方法或者方法的集合。
SLF4J如何支持Log4j
-
观察者模式:当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知它的依赖对象。观察者模式属于行为型模式。
GRPC是如何支持流式请求的 -
其他模式
1.2.3.2. java语言特性
-
JUC:java并发工具包
-
集合类:hashmap,treemap实现
hashmap:- 数组加链表实现:hashcode计算存入数组的位置,链表解决hash散列冲突;链表节点是kv;填充因子的作用,扩容时rehash的机制。
- 容量必须2次幂:因为可以通过按位与操作计算余数比求模要快;
- 并发读写风险:非线程安全,多线程put,容量超过填充因子时进行rehash;hash避免尾部遍历采用的是头插法,多线程场景可能死循环。
ConcurrentHashMap
-
1.8之前分段锁Segment
-
1.8自旋锁CAS乐观锁模式,并发度较高性能一般。
-
解决hash冲突链表的顺序查找问题;默认链表长度大于8小于64启用红黑树。
-
动态代理和反射:orm框架中使用代理类;rpc调用会使用反射机制
-
数据类型:空间占用int,float4字节,long,double8字节,byte1字节
-
对象引用:1.强引用不会被回收2.弱引用每次gc都会回收3.软引用内存空间不足回收4.跟引用队列联合使用跟踪对象垃圾回收的过程。
-
异常机制:异常try..cache处理流程;error-exception区别
Error(错误)是系统中的错误,是在程序编译时出现的错误或系统崩溃,虚拟机错误,内存空间不足,方法调用栈溢,遇到这样的错误,建议让程序终止。
Exception(异常)表示程序可以处理的异常,可以捕获且可能恢复。
v1.8
lambda表达式,代码简洁,并行计算
Metaspace替换PermGen:前者使用本地内存,不在虚拟机,提升对元数据处理,提升gc效率;方便后续hotsport与其合并
v1.11
ZGC:为大内存堆设计,能实现10ms以下的回收停顿;
内置httpclient
1.2.3.3. 面试考察点
-
基本概念和原理:正确清晰
-
实现方式与使用姿势:hashmap,单例模式
-
经常使用到的知识点:linux命令解决什么问题
-
应用中容易犯错的点:==与eques区别?对象强引用使用不当导致内存泄露
==比较**堆内存**地址;引用类型:默认情况下,比较的是地址值,重写方法比较的是内容值.
-
与面试方向相关的知识点:岗位:中间件研发就要考察存储,网络
加分项 -
知识点与典型业务场景关联:还能指出那种框架使用那种模式,处理什么场景问题,有什么效果
-
以反例来描述实际场景中误用的危害:大量反射对性能有影响
-
知识点相关的优化点:tcp time_wait时调参加快回收
-
知识点相关的最新技术趋势:concurrentMap1.8的改进细节,quic的实现
-
在比较了解的情况下增加回答内容深度;tcp滑动窗口涉及到流量和拥塞控制,不同的解决拥塞算法;面试官一般追问,如果不了解可能适得其反。
流量控制:防止发送方发的太快,耗尽接收方的资源,从而使接收方来不及处理;针对接收端接收量告诉发送端窗口批量发送指定量的数据.
拥塞控制:防止发送方发的太快,使得网络来不及处理,从而导致网络拥塞
加法增加:是指执行拥塞避免算法后,在收到对所有报文段的确认后(即经过一个往返时间),就把拥塞窗口cwnd增加一个MSS大小,使拥塞窗口缓慢增大,以防止网络过早出现拥塞
乘法减少:出现一次超时(即出现一次网络拥塞),就把慢开始门限值ssthresh设置为当前的拥塞窗口值乘以0.5
流量控制和拥塞控制区别:
(1)丢包位置不同
流量控制丢包位置是在接收端上
拥塞控制丢包位置是在路由器上
(2)作用的对象不同
流量控制的对象是接收方,怕发送方发的太快,使得接收方来不及处理
拥塞控制的对象是网络,怕发送发发的太快,造成网络拥塞,使得网络来不及处理
真题汇总
1.资源占用,切换效率,通讯方式2.上下文切换代价,会保存寄存器,栈等线程相关现场,由用户态切换到内核态,可以通过vmstat命令查看线程上下文状况。6.dns解析,tcp建连,http请求与响应。
1.2.4. 深入浅出jvm
性能调优:偏重实际经验;编译器优化和执行模式偏重理论
内存模型都分别保存哪些数据,作用;
类加载,双亲委派加载机制,常用类加载器分别加载哪些类
分代思想:常用垃圾回收机制和算法思路和场景
jvm常见参数作用,参数调优一句,常用分析工具分析哪些问题使用方法
执行模式:了解解释编译混合模式区别,java7分层编译技术,jit即时编译技术,OSR(栈上替换OSR) c1针对client,c2分别针对server场景;可以了解java10 graalvm编译器
编译优化:前段编译器javac编译过程,ast抽象语法树,编译期优化和运行期优化;
优化技术:公共子表达式消除,方法的内敛,逃逸分析,栈上分配,同步消除
1.2.4.1. jvm内存模型
- 各部分功能2.哪些线程共享,哪些私有
方法-栈帧:局部变量表,操作栈,动态链接方法出口信息;执行java方法用栈,native用本地犯法栈
计数器:线程-计数器保存当前线程字节码执行的位置;只为java方法服务;native方法计数器为空
方法区:各个线程共享区,类信息,常量,静态变量,jit编译器优化的一种永久代码等。metaspace或者永久代都是方法区的一种实现而已。
JMM内存可见性:因为a线程读写共享变量副本(在工作内存)都要重新写回主内存,b线程再从主内存读取到自己的工作区;由于指令重排序的关系,读写可能被打乱所以要保证jmm内存就能的原子性,可见性,有序性。
原子性:synchronized通过两个高级字节码指令monitorenter,monitorexit实现原子性
可见性:valatile强制变量的赋值刷新回主内存,强制变量的读取重新加载到工作内存,保证可见性,不同的线程总是能看到该变量的最新值。
有序性:volatile阻止指令重排序,保证变量读写有序性;happen-befores原则:保证程序顺序性,语义串行型;同一个锁解锁一定发生在再次枷锁之前;原则的传递性,现成的启动中断,终止规则等。
1.2.4.2. 类加载机制:加载与卸载
加载机制
加载:分为加载-链接-初始化;链接分为:验证-准备-解析三步
加载:文件到内存的过程,通过全类名,查找字节码文件,实例化Class对象;
验证:是对类文件内容验证,确保文件符合要求不会对虚拟机安全危害
准备:进行内存分配,对static修饰的变量分内存并赋初始值0或null;也不包含final修饰的变量,因为final修饰的变量在编译时就分配了内存。
解析:符号引用替换为直接引用,直接指向目标的指针或者偏移量
初始化:主要完成静态块执行,静态变量赋值;类加载最后阶段,如果父类没初始化,就先对父类初始化;只有对类主动使用才会初始化:1.创建类实例,2.访问类静态方法变量3.classforname反射类的时候4.子类被初始化的时候
jvm自带的类加载器记载的类不会被卸载(gc);用户自定义的加载器才会被卸载;
常用类加载器
不同的加载器加载不同的目录下的文件橙色字体
类加载双亲委派模式:先把类加载的请求委托给父类加载器,如图中蓝色箭头,如果父类还有父类加载器就网上传递;直至启动加载器加载;如果父祖类加载器无法加载,自己才去加载入向下箭头;1.避免类重复加载2.避免javaapi被污染。
分代回收
引用计数法:对象引用次数,无法解决对象循环引用的问题。
复制算法:浪费资源
标记清除算法:内存碎片
G1算法:取消新老代物理划分;仍然是分代收集器;把内存分为region方格,一部分年轻带,一部分老年代,一部分巨型对象。老年代回收也对年轻代回收;初始标记对跟对象标记,最终标记完成三次标记的标记周期,复制清除阶段优先对可回收空间大的进行回收即garbage first(G1);每次只清理一部分,回收后会整理新老年代碎片;可以设置region大小(<32m),期望gc停顿时间。
ZGC算法:针对TB级别的堆大内存垃圾回收,10ms以下的停顿。
着色指针:64位平台一个指针可用位是64位,zgc限制支持4gb的堆,这样寻址只需要42位,这样剩下的22位可以保存其他信息。
读屏障:解决gc线程和应用线程并发冲撞的问题,读屏障只需要对单个对象锁定,不需要gc STW;所以可以应用程序并发处理。
并发处理
基于Region(不可调大小):但是没有分代,region动态创建销毁分配大小
内存压缩(整理):移动合并处理碎片
ZGC并发标记结束会有短暂停顿stw;root重定位时间跟root对象数量,重定位集与活动数量集的比率
1.2.4.3. 考察点
1.2.4.4. 加分项
1.2.4.5. 真题汇总
-
简单描述一下
jvm内存模型确认是jvm模型还是java堆内存访问的模型
-
什么情况下会出发FullGC
年轻代晋升,老年代空间不足,永久带空间不足; -
java类加载器集中,关系是怎样的?
- 启动类加载器,由C++实现,没有父类。
- 拓展类加载器(ExtClassLoader),由Java语言实现,父类加载器为null
- 系统类加载器(AppClassLoader),由Java语言实现,父类加载器为ExtClassLoader
- 自定义类加载器,父类加载器肯定为AppClassLoader。
-
双亲委派机制的加载流程是怎样的?有什么好处?
1.避免类重复加载2.避免javaapi被污染。
-
1.8为什么用metaspace替换带哦PermGen?metaspace保存在哪里?
“PermGen space”其实指的就是方法区,如果jsp页面过多就会内存溢出,所以放到metaspacke(元空间Native堆中)
-
编译期会对指令做哪些优化?(简单描述编译器的指令重排)
指令重排的目的是为了在不改变程序执行结果的前提下,优化程序的运行效率。需要注意的是,这里所说的不改变执行结果,指的是不改变单线程下的程序执行结果。
编译优化:string s+=“aa”编译后就是stringbuilder
其实想说明的是,用语法描述的语义 经过编译器的优化 可以转化为另外一种语法,但是语义不变。
例如自动装箱以及拆箱,其实只是在编译器层面的支持
-
简单描述一下volatile可以解决什么问题?如何做到的?1.强制主内存读写同步2.防止指令集重排序
-
简单描述一下GC的分代回收
-
G1垃圾回收算法与CMS的区别有哪些?
这个现在是垃圾回收器的标配,G1和CMS也不例外。但是G1同时回收老年代和年轻代,而CMS只能回收老年代,需要配合一个年轻代收集器
导致CMS Full GC的可能原因主要有两个:Promotion Failure和Concurrent Mode Failure,前者是在年轻代晋升的时候老年代没有足够的连续空间容纳,很有可能是内存碎片导致的;后者是在并发过程中jvm觉得在并发过程结束前堆就会满了,需要提前触发Full GC。CMS的Full GC是一个多线程STW的Mark-Compact过程,,需要尽量避免或者降低频率 -
对象引用有哪几种方式,有什么特点?
1.强引用不会被回收2.弱引用每次gc都会回收3.软引用内存空间不足回收4.虚引用也称为幽灵引用或幻影引用。虚引用的 get 方法永远返回 null,须要关联一个 ReferenceQueue 引用队列联合使用跟踪对象垃圾回收的过程。
-
使用过哪些JVM调试工具,主要分析哪些内容? jstack用于打印出给定的java进程ID或core file或远程调试服务的Java堆栈信息
1.2.5. 并发与多线程
1.2.5.1. 汇总
对资源的锁定和等待会产生死锁
- 产生死锁的四个条件,怎么通过破坏四个条件,避免死锁?
-
系统资源的竞争
系统资源的竞争导致系统资源不足,以及资源分配不当,导致死锁。 -
进程运行推进顺序不合适
进程在运行过程中,请求和释放资源的顺序不当,会导致死锁。-
互斥条件:一个资源每次只能被一个进程使用;
-
请求与保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,吃着碗里占着锅里.
-
不可剥夺条件:进程所获得的资源在未使用完毕之前,不能被其他进程强行夺走
-
循环等待条件: 若干进程间形成首尾相接循环等待资源的关系;
四个条件都满足就死锁.
-
-
死锁避免:基本思想:系统对进程发出的每一个系统能够满足的资源申请进行动态检查,操作系统能保证所有进程在有限时间内得到需要的全部资源,则系统处于安全状态否则系统是不安全的.安全就给资源
-
死锁预防:我们可以通过破坏死锁产生的4个必要条件来 预防死锁,由于资源互斥是资源使用的固有特性是无法改变的。
-
竞争条件和临界区的概念?
两个线程访问同一个资源而且与线程访问资源时的顺序有关的这样一种情形就叫竞争条件。 导致竞争条件发生的代码片段就叫临界区
-
线程通信方式(即协作机制wait,notify,notifyall)
sleep释放cpu进入就绪状态,wait释放锁,进入wait 池,notify唤醒wait的线程进入就绪状态后两着必须在同步代码中使用 -
线程机制:THreadlocal->保证线程独享的数据,实现机制
Fork/join->用于大任务的分割与汇总,任务工作的窃取办法
volatile->数据可见性保证
Interrupt->线程中断机制
1.2.5.2. 线程状态转换:获取锁失败进入blocked;两种waiting都是Object.notify唤醒。
1.2.5.3. CAS(Compare And Swap)与ABA:乐观锁实现
ABA问题不一定影响结果解决的办法是增加标志位或者时间戳
1.2.5.4. synchronized实现原理
java对象内存包含三部分:
1,对象头:保存了锁标志位和指向monitor对象的起始地址;monitor中onwer指向获取monitor对象的线程,entrylist,waitset分别保存进入|等待的线程队列。
2,实例数据
3,对齐填充字节
对于方法同步实现是增加ACC_SYNCHRONIZED标志位
对于代码块同步:通过monitorenter和exit实现
针对jvm获取锁的方式通过锁升级优化实现:偏向锁优先统一再次获取锁,如果失败升级为CAS轻量锁,如果再失败就会进行短暂自旋,防止线程挂起;如果再失败就会升级为重量级锁。
1.2.5.5. AQS(AbstractQueuedSynchronizeer)与Lock
获得锁的线程需要获得某个条件时会进入等待队列,当条件满足时线程会从等待队列进入同步队列,重新获取对锁的竞争!
ReentrantLock:是独占锁分为公平和非公平所两种实现,新来的线程有没有可能比同步队列中的线程更早获得锁,有可能就是非公平。
Semaphore:也是基于AQS,不过它是共享锁。
1.2.5.6. 线程池使用场景
除了第五个线程池外其他都是通过ThreadPoolExecutor不同的构造参数区别创建的。
线程池参数介绍:
FixedPool:coreSize与maxSize设置固定大小为什么采用LinkedQueue无界队列?
cachePool:核心线程设置为0,max设置为Integer.max_value,把缓冲队列设置成SynchronousQueue只要没有空闲线程就会创建。
SchedulPool:使用delyedActiveQueue(延迟队列),安延迟事件获取任务的优先级。
1.2.5.7. 线程池执行流程(executor或者submit提交任务给线程,submit可以返回future对象)
1.2.5.8. JUC常用工具
原子操作
锁操作和异步操作线程类
写饥饿:读操作频繁,写没法枷锁
常用阻塞队列,多线程协作类,集合类
1.2.5.9. 面试考察点:同步异步看是否在一个线程执行的?阻塞不阻塞看是否等待?
1.2.5.10. 加分项
1.2.5.11. 真题汇总
-
如何是想一个生产者与消费者模型(锁,信号量,线程通信,阻塞队列等不同方式)
-
如何理解线程的同步与异步,阻塞与非阻塞?同步异步看是否在一个线程执行的?阻塞不阻塞看是否等待?
-
线程池处理任务的流程是怎样的?
- 提交任务后,线程池先判断线程数是否达到了核心线程数(corePoolSize)。如果未达到线程数,则创建核心线程处理任务;否则,就执行下一步;
- 接着线程池判断任务队列是否满了。如果没满,则将任务添加到任务队列中;否则,执行下一步;
- 接着因为任务队列满了,线程池就判断线程数是否达到了最大线程数。如果未达到,则创建非核心线程处理任务;否则,就执行饱和策略,默认会抛出RejectedExecutionException异常
-
wait与sleep有什么不同:
1.wait属于object,sleep属于thread类
2.wait会释放锁,sleep不会
3.wait必须在同步快中使用,sleep可以任何地方
4.sleep需要捕获异常,wait不适合 -
Synchronized和ReentrantLock有什么不同?各适合什么场景?
-
读写锁适用于什么场景?ReentrantReadWriteLocak是如何实现的?
读写锁适合读并发多写少的场景,另外一个解决这种场景的方法是使用CopyOnWritexxxxx -
线程之间如何通信
-
wait ,notify;2. lock同步机制;3.sychronized机制
-
保证线程安全的方法有哪些
CAS,ThreadLocal,Lock,sychronized -
如何尽可能提高多线程并发性能?
尽量减少临界区范围,使用Threadlocal减少线程切换,使用读写锁机制 -
ThreadLocal用来解决什么问题?ThreadLocal是如何实现的?
Threadlocal不是解决线程共享变量的问题而是解决数据隔离的问题 -
死锁的产生条件?如何分析是否有线程死锁?
-
在实际工作中遇到过什么样的并发问题,如何发现(排查)并解决的。使用压测工具分析哪一环节并发问题
HTML静态化、图片服务器分离、数据库集群、库表散列、缓存、镜像、负载均衡、CDN加速技术。
1.2.6. 数据结构与算法
1.2.6.1. 知识点汇总数据结构及算法
1.2.6.2. 从搜索树到B+数
二叉搜索数和红黑树
B-和B+树
1.2.6.3. 字符创匹配问题
解题技巧
1.2.6.4. TOPK
topk变种从有序中找最小
1.2.6.5. 常用算法场景介绍和解题方法
1.2.6.6. 面试考察点
加分项
1.2.6.7. 真题汇总
- 各种排序算法实现和复杂度,稳定性
- 二叉树的前中后遍历
- 翻转句子中单词的顺序
- 用栈模拟队列(或队列模拟栈)
- 对10亿个树进行排序,限制内存为1g:分治思想
- 去掉(或找出)两个数组中重复的数字:排序或者hash
- 将一颗二叉树转换成其镜像
- 确定一个字符串中的括号是否匹配
- 给定一个开始次,一个结束次,一个字典,如何找到从开始次到结束词的最短单词接龙路径:深度优先搜索节点
- 如何查找两个二叉树节点的最近公共祖先:递归非递归都可以。
1.3. 应用模块
1.3.1. 常用工具集
1.3.1.1. JMC(JAVA MISSION Control 1.7)
jvm浏览器:可以列出正在运行的java程序jvm,每个jvm实例叫做一个jvm链接;使用jdp java发现协议链接到本地或者远程jvm。
JMX:JAVA管理扩展规范,扩展MBean,进行监控管理
JFR(java飞行计数器):主要用于jvm问题分析
线上调试神器--btrace
其他jvm工具
1.需要查看gc详细日志,需要使用jinfo修改jvm参数printGCDetail设置动态生效
2.需要分析堆内存泄露风险时,通过jmap,或者jstat统计分析堆中持续增长的可疑对象
3.当某一时刻所有服务都出现耗时较高可疑通过jstack观察GC回收状况,是不是stw过高
4.jvm某个服务卡死或者停止处理,jstack查看线程栈,看看是否多个线程blocked状态发生死锁。
5.上线后性能达不到预期,可以使jmc分析jvm运行信息看看哪些热点方法可以优化,哪些线程竞争可以避免。
1.3.1.2. Git常用命令
工作流(分支管理规范分以下三种)
1.3.1.3. linux常用分析工具(strace可以调java native问题)
1.3.1.4. 考察点
- 了解常用jvm分析工具
- git常用操作和工作流:rebase修改历史记录,merge提交comimt合并修改
- linux下常用的分析工具
加分项 - 主动出击体现知识广度
- 体现实战能力
- 上线前用jmc进行性能profile,发现优化了哪些问题
- 项目方案:对两个方案使用jmetty性能测试,验证方案实现的性能
1.3.1.5. 真题汇总
- 排查jvm问题的哪些工具(你遇到过什么问题,如何排查,如何解决的)
- git合并代码有哪两种方法?区别是什么?
- Git与svn有哪些差异
- 你所在团队项目开发使用什么样的工作流?有什么有点?
1.3.2. 常用框架
知识汇总
1.3.2.1. Spring
1.3.2.1.1. spring中的基本概念
框架组件红框重要
1.3.2.1.2. spring机制与实现
1.3.2.1.3. Spring应用
1.3.2.1.4. springcontext初始化流程
1.3.2.1.5. bean的声明周期
1.3.2.1.6. Spring扩展接口
1.3.2.1.7. Springboot详解
1.3.2.2. netty
1.3.2.2.1. netty线程模型
RPC介绍
1.3.2.3. mybatis
处理流程
考察点及加分项
1.3.2.4. 真题汇总
- ssh与ssm框架组合的区别是什么?是什么?分别区别?
- 描述一下springConet的初始化过程?
- 介绍一下Bean的声明周期及作用域
- spring配置中placeholder占位符是如何替换的?有什么办法可以实现自定义配置替换?
通过beanfactoryprocess后置处理器进行占位符替换,如果自定义可以扩展placehodlerhandler实现。 - springmvc工作流程是怎样的?
从mapping查找handler,执行handler,执行完返回modelAndView,视图解析返回视图几步。 - spring如何解决循环依赖?
- 构造器循环依赖:通过创建bean中的标志池,来判断是否发生循环依赖
- set循环依赖:通过引入objectFactory来解决
- Bean构造方法,@PostConstruct注解,InitializingBean,Init-method的执行顺序是怎样的?就是题目中的顺序。
- netty中有哪些重要的对象?
channel,socket,eventloop等。 - RPC与http的区别是什么?什么场景适合rpc,什么场景适合http?
- rpc动态代理调用http通过client调用
- http经过dns解析,4/7层网络模型;rpc一般点对点
- rpc提供丰富服务治理熔断,负载均衡,http对跨语言支持比较好。
- RPC交互流程是怎样的?
- 介绍一下Mybatis的缓存机制
- Mybatis如何配置动态SQL?有哪些动态sql标签?
1.3.3. 高并发架构基石-缓存
1.3.3.1. MC内存结构
1.3.3.2. Redis
介绍:
1.3.3.2.1. Redis数据结构:使用字典存储不同的类型数据;所有对象封装成redisObject;
1.3.3.2.2. 缓存常见问题
考察点及加分项
1.3.3.3. 真题汇总
- Redis和Memcache的区别,该如何选用
- 你用过哪些redis的数据结构,用在什么场景
- redis持久化方式有哪些?区别是什么?
- Redis过期机制是怎样的?redis有哪些淘汰策略
- 如何保证redis高并发和高可用?读写分离,多从库,多端口实例;从新选主
- 如何使用redis实现延迟队列,如何使用redis实现分布式锁?
redis的sortedset做延迟队列:使用时间戳做score,消费方指定zrangebyscore获取指定延时之前的数据。
分布式锁可以用SETNX (是SET if Not eXists的简写):使用setnx设置key如果返回1设置成功获取锁成功;返回0失败,设置px参数设置超时时间,防着锁的实例宕机后造成死锁;严格场景可以考虑writelock方案。
1.3.4. 消息队列和数据库
汇总
1.3.4.1. 消息队列kafka原理和架构
- kafka保证分区内有序,分区间不能保证:数据0-1000二号分区1001-2001一号分区:ISR同步复本集。都是在leader上读写。
消息发布/消费流程
1.3.4.2. MYSQL最佳调优和实践
事务特性ACID
原子性:操作要么都成功要么失败。
一致性:事务的执行,不能破坏完整性和一致性,多表操作,多表要么是事务前值,要么是事务之后的值。
隔离性:多个用户访问数据库,数据库为每个用户执行的事务要隔离,不能相互干扰。
持久性:一旦提交并执行成功,就是永久性的改变;即便数据库宕机,也不会丢失事务的操作。
1.3.4.2.1. 事务并发问题与隔离级别:脏读,不可重复读,幻读问题.
1.3.4.2.2. 事务分类
1.3.4.2.3. mysql汇总
1.3.4.2.4. mysql 索引
1.3.4.2.5. mysql调优
1.3.4.2.6. 考察点和加分项
1.3.4.2.7. 真题汇总
- 使用过消息队列码?什么场景?用来解决什么问题?
- 队列如何保证可靠性?发送保证投递成功,消息自身高可用,消费方处理完修改offset;kafka同步异步,修改ack。
- MQ有可能重复消费码?如何解决:1.对消息处理实现幂等消除重复消息的影响2.使用redis消息去重
- 在数据库查询语句慢时如何优化?创建索引,减少关联查询,优化查询条件
- 数据库事务有哪些特性,隔离级别有几种
- 如何对sql语句优化?根据调优原则回答。
1.4. 综合模块
1.4.1. 架构演进之路和前沿技术
1.4.1.1. 单体架构和微服务架构
服务规模变大时为了解决耦合,出现了soa面向服务架构最后演变成微服务高内聚低耦合
1.4.1.2. 分布式CAP(一致,可用,容错)原则与BASE理论
1.4.1.3. 云原生服务及12要素
下一代架构Service Mesh
微服务与servicemesh区别
1.4.2. 容器化
1.4.2.1. docker作用及其原理
1.4.2.2. k8s(kubernetes 因为k->s有8个字母)
介绍
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)