秋招面经五(字节、拼多多、美团、网易)
字节跳动
一面(2020-8-11)
1、操作系统内存管理
2、计算机的32位和64位是指的是什么
一次计算可以处理的最大数据长度
3、进程调度算法
- 先来先服务
- 短进程优先
- 最高响应比优先:响应比R = (等待时间+执行时间)/执行时间
- 时间片轮转:按照分配的时间片进行轮转,每次轮转的时候使用先来先服务进行选取进程
- 多级反馈队列:设置多个不同优先级的队列,优先级高的队列,分配的时间片时间较长,低优先级的队列,分配的时间片较短。与此同时,进程会随着占用时间片内是否完成而在不同队列中移动。一般对于IO密集型的进程,会存放在高优先级队列中,对于CPU密集型进程,会快速的下降到低优先级队列中。
- 公平共享调度算法
4、http的请求头里面都有什么
请求方法,请求url,http协议及版本
5、栈和队列
两者的区别特点
6、Object中有哪些方法
hashcode,equals
wait、notify
toString、
一面(2020-8-18 )
1、mybatis里面如何防止SQL注入
1.1、在mybatis中两个符号${}和#{}的区别
- #{}是预编译处理, ${}是字符串替换。
- Mybatis
在处理#{}时,会将 sql 中的#{}替换为?号,调用 PreparedStatement 的 set 方法来赋值
; - Mybatis 在处理
{}替换成变量的值
使用#{}可以有效的防止 SQL 注入,提高系统安全性
2、dispatchservlet(springMVC工作流程)
- 用户发送请求至前端控制器 DispatcherServlet。
- DispatcherServlet 收到请求调用 HandlerMapping 处理器映射器。
- 处理器映射器找到具体的处理器(可以根据 xml 配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给 DispatcherServlet。
- DispatcherServlet 调用 HandlerAdapter 处理器适配器。
- HandlerAdapter 经过适配调用具体的处理器(Controller,也叫后端控制器)
- Controller 执行完成返回 ModelAndView。
- HandlerAdapter 将 controller 执行结果 ModelAndView 返回给 DispatcherServlet。
- DispatcherServlet 将 ModelAndView 传给 ViewReslover 视图解析器。
- ViewReslover 解析后返回具体 View
- DispatcherServlet 根据 View 进行渲染视图(即将模型数据填充至视图中)。
- DispatcherServlet 响应用户
3、LinkedHashMap底层数据结构
底层是hashmap和双向链表,每一个entry都有一个前项entry和一个后项entry
4、zset的底层数据结构
除了跳跃表之外的,ziplist,skiplist
5、输入网址之后做了哪些事情
- DNS查找浏览器缓存,查找本地缓存host文件,查询本地DNS服务器,查找根域名服务器,顶级域名服务器(com , org ...),权威域名服务器(企业),返回域名对应的ip地址
- 得到IP地址发送http请求
- TCP三次握手,建立连接通道
- 传输数据到服务端,服务端进行处理
- 服务端响应数据并返回
- 断开连接
- 浏览器解析html数据并进行渲染展示
6、多个AOP的时候,执行的顺序
https://www.cnblogs.com/fanguangdexiaoyuer/p/10562069.html#_label0
可以设置不同aop的order来实现执行的顺序,order越小越是最先执行,更重要的是最先执行的最后结束。spring AOP就是面向切面编程,什么是切面,画一个图来理解下:
7、事务的可重复读是怎么实现的?
mvcc多版本控制,每个事务内只能读取比当前事务版本号低的数据。
8、kafka是全局有序的么?
全局无序,在同一个topic下,各个分区内部是有序的,使用offset来进行标识顺序。
如果对某些业务需要实现有序的话,我们可以设置这条消息的key,来保证所有这个key的消息都被分配到同一个分区中。
在kafka的分区器中,首先检查ProduceRecord中是否有key,如果有key的话,则使用散列算法计算对应的分区号,这样就可以实现所有相同key的消息都在同一个分区下,保证这个key的消息都是有序的。此时分区器分到的分区是所有分区
。
如果produceRecord中,没有key的话,那么分区器将自己使用使用轮询来分配,但是可分配的分区均在可用分区
中分配,而不是所有分区。
9、Redis单线程为什么这么快?
- 纯内存操作
- 单线程
- 高效的数据结构
- 合理的数据编码
- 其他方面的优化
拼多多
一面(2020-8-14)
1、Redis中一个keyset里面存储100W个键的时候,怎么办?
在Redis集群中,总共有16000多个插槽(slot),然后集群会将每一个key的有效部分(或者整个key)根据CRC16进行散列,对应到一个特定的插槽中,而集群中的每一台服务器,都只是负责其中一部分插槽。通过这种集群方式,Redis实现整体的内存分配。
面对上面的问题,我们可以采取如下策略
:
对这个key进行分组,比如传入进来的key-value为:<user:userId , value>,然后我们对这个key进行分组。比如说根据value的值,value在区间[0,100]时,将其分配给A组,此时的key变为:user:userid.A , 当value在区间[100,200]之内时,分配给B组,此时对key进行改造,成为了:user:userid.B。通过这种方式,可以将一个key-set结构存储量很大的情况,转换到不同的key中,散列到不同的slot内,相当于将这个key进行散列到了集群中的不同节点中。
二面(2020-8-22)
1、库函数和系统函数
- 系统函数(系统调用):系统调用实际上是指底层的一个调用,就是内核提供的、功能十分强大的一系列的函数。这些系统调用是在内核中实现的。是操作系统为用户态运行的进程和硬件设备(如CPU、磁盘、打印机等)进行交互提供的一组接口,即就是设置在应用程序和硬件设备之间的一个接口层。可以说是操作系统留给用户程序的一个接口。
- 库函数:顾名思义是把函数放到库里,是把一些常用到的函数编完放到一个文件里,供别人用。别人用的时候把所在的文件名用#include<>加到里面就可以了,一般放到lib文件里。库函数一般分为两类:一种是C语言标准规定的库函数,一类是编译器特定的库函数。libc就是一个C标准库,里面放着一些基本的函数,这些函数都被标准化了。 库函数调用通常用于应用程序中对一般文件的访问,库函数调用是系统无关的,因此移植性好。
2、阻塞io和非阻塞io
阻塞IO为BIO,非阻塞IO为NIO
3、多个消费者能不能替代kafka
4、ES怎么搭建的
5、awk
属于文本的操作工具,与grep,sed并称三大文本工具。
6、epoll函数
6.1 epoll模型架构
对比其他模型的问题,epoll的改进如下:
(1)支持一个进程打开大数目的socket描述符(FD)select 最不能忍受的是一个进程所打开的FD是有一定限制的,由FD_SETSIZE设置,默认值是2048。对于那些需要支持的上万连接数目的IM服务器来说显然太少了。这时候你一是可以选择修改这个宏然后重新编译内核,不过资料也同时指出这样会带来网络效率的下降,二是可以选择多进程的解决方案(传统的 Apache方案),不过虽然linux上面创建进程的代价比较小,但仍旧是不可忽视的,加上进程间数据同步远比不上线程间同步的高效,所以也不是一种完美的方案。不过 epoll则没有这个限制,它所支持的FD上限是最大可以打开文件的数目,这个数字一般远大于2048,举个例子,在1GB内存的机器上大约是10万左右,具体数目可以cat /proc/sys/fs/file-max察看,一般来说这个数目和系统内存关系很大。
(2)IO效率不随FD数目增加而线性下降传统的select/poll另一个致命弱点就是当你拥有一个很大的socket集合,不过由于网络延时,任一时间只有部分的socket是"活跃"的,但是select/poll每次调用都会线性扫描全部的集合,导致效率呈现线性下降。但是epoll不存在这个问题,它只会对"活跃"的socket进行操作---这是因为在内核实现中epoll是根据每个fd上面的callback函数实现的。那么,只有"活跃"的socket才会主动的去调用 callback函数,其他idle状态socket则不会
,在这点上,epoll实现了一个"伪"AIO,因为这时候推动力在os内核。在一些 benchmark中,如果所有的socket基本上都是活跃的---比如一个高速LAN环境,epoll并不比select/poll有什么效率,相反,如果过多使用epoll_ctl,效率相比还有稍微的下降。但是一旦使用idle connections模拟WAN环境,epoll的效率就远在select/poll之上了。
(3)使用mmap加速内核与用户空间的消息传递这点实际上涉及到epoll的具体实现了。无论是select,poll还是epoll都需要内核把FD消息通知给用户空间,如何避免不必要的内存拷贝就很重要,在这点上,epoll是通过内核于用户空间mmap同一块内存实现的。而如果你想我一样从2.5内核就关注epoll的话,一定不会忘记手工 mmap这一步的。
6.2 epoll为什么这么高效
①从上面的调用方式就可以看出epoll比select/poll的一个优势:select/poll每次调用都要传递所要监控的所有fd给select/poll系统调用(这意味着每次调用都要将fd列表从用户态拷贝到内核态,当fd数目很多时,这会造成低效)。而每次调用epoll_wait时(作用相当于调用select/poll),不需要再传递fd列表给内核,因为已经在epoll_ctl中将需要监控的fd告诉了内核(epoll_ctl不需要每次都拷贝所有的fd,只需要进行增量式操作)。所以,在调用epoll_create之后,内核已经在内核态开始准备数据结构存放要监控的fd了。每次epoll_ctl只是对这个数据结构进行简单的维护。
② 此外,内核使用了slab机制,为epoll提供了快速的数据结构:
在内核里,一切皆文件。所以,epoll向内核注册了一个文件系统,用于存储上述的被监控的fd。当你调用epoll_create时,就会在这个虚拟的epoll文件系统里创建一个file结点。当然这个file不是普通文件,它只服务于epoll。epoll在被内核初始化时(操作系统启动),同时会开辟出epoll自己的内核高速cache区,用于安置每一个我们想监控的fd,**这些fd会以红黑树的形式保存在内核cache里,以支持快速的查找、插入、删除。**这个内核高速cache区,就是建立连续的物理内存页,然后在之上建立slab层,简单的说,就是物理上分配好你想要的size的内存对象,每次使用时都是使用空闲的已分配好的对象。
③ epoll的第三个优势在于:当我们调用epoll_ctl往里塞入百万个fd时,epoll_wait仍然可以飞快的返回,并有效的将发生事件的fd给我们用户。这是由于我们在调用epoll_create时,内核除了帮我们在epoll文件系统里建了个file结点,在内核cache里建了个红黑树用于存储以后epoll_ctl传来的fd外,还会再建立一个list链表,用于存储准备就绪的事件,当epoll_wait调用时,仅仅观察这个list链表里有没有数据即可。有数据就返回,没有数据就sleep,等到timeout时间到后即使链表没数据也返回。所以,epoll_wait非常高效。而且,通常情况下即使我们要监控百万计的fd,大多一次也只返回很少量的准备就绪fd而已,所以,epoll_wait仅需要从内核态copy少量的fd到用户态而已。那么,这个准备就绪list链表是怎么维护的呢?当我们执行epoll_ctl时,除了把fd放到epoll文件系统里file对象对应的红黑树上之外,还会给内核中断处理程序注册一个回调函数,告诉内核,如果这个fd的中断到了,就把它放到准备就绪list链表里。所以,当一个fd(例如socket)上有数据到了,内核在把设备(例如网卡)上的数据copy到内核中后就来把fd(socket)插入到准备就绪list链表里了。
奇安信
一面(2020-8-15)
1、springboot的了解
2、spring源码了解
3、ES的分片的理解
就是有多少个备份
4、手撕代码
二面(2020-8-15)
1、死锁实现,手撕代码
2、解除死锁,手撕代码
三面(2020-8-15)
1、对奇安信的了解
2、对奇安信的类比
科大讯飞
一面(2020-8-20)
1、看过什么书
2、有没有看过源码
二面(2020-8-25)
1、es除了搜索还能做什么?
可以做搜索框中的前缀搜索,可以做复合查询,可以做存储系统
秋招
中兴
一面(2020-8-12)
1、设计模式MVC三层架构与spring编写业务逻辑代码时候的三层
设计模式MVC
- M(model模型层):一般对应service和dao层
- V(view视图层):对应的是返回的视图view
- C(controller控制层):一般对应着controller层
2、面向对象的特点
封装,多态,继承
3、string的特点
安全的类
4、tcp是每个数据报都要收到应答么?
不是的,按照ack的数据,比如ack = 100,表示前100都收到了
5、子类可以使用父类的protected方法么?
可以
6、十大排序算法
7、交换机属于哪一层
数据链路层
8、堆和栈的区别
https://blog.csdn.net/wolenski/article/details/7951961
堆像一棵倒过来的树 堆就不同了,堆是一种经过排序的树形数据结构,每个结点都有一个值。通常我们所说的堆的数据结构,是指二叉堆。堆的特点是根结点的值最小(或最大),且根结点的两个子树也是一个堆。由于堆的这个特性,常用来实现优先队列,堆的存取是随意,这就如同我们在图书馆的书架上取书,虽然书的摆放是有顺序的,但是我们想取任意一本时不必像栈一样,先取出前面所有的书,书架这种机制不同于箱子,我们可以直接取出我们想要的书。
映客直播
一面(2020-9-5)
1、堆和栈的区别
堆(英语:heap)是计算机科学中一类特殊的数据结构的统称。堆通常是一个可以被看做一棵树的数组对象。堆总是满足下列性质:
- 堆中某个节点的值总是不大于或不小于其父节点的值;
- 堆总是一棵完全二叉树。
将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。常见的堆有二叉堆、斐波那契堆等。
堆是非线性数据结构,相当于一维数组,有两个直接后继。
堆的定义如下:n个元素的序列{k1,k2,ki,…,kn}当且仅当满足下关系时,称之为堆。
(ki <= k2i,ki <= k2i+1)或者(ki >= k2i,ki >= k2i+1), (i = 1,2,3,4...n/2)
若将和此次序列对应的一维数组(即以一维数组作此序列的存储结构)看成是一个完全二叉树,则堆的含义表明,完全二叉树中所有非终端结点的值均不大于(或不小于)其左、右孩子结点的值。由此,若序列{k1,k2,…,kn}是堆,则堆顶元素(或完全二叉树的根)必为序列中n个元素的最小值(或最大值)。
2、输入域名之后的流程
https://segmentfault.com/a/1190000012092552
当我们在浏览器中输入请求URL之后:
- DNS域名解析
- 首先查内存缓存
- 然后查磁盘的host文件
- 然后查本地DNS服务器
- 然后查根域名服务器(全球13个)
- 然后向下查顶级域名服务器(.com/.org)等
- 最后查权威域名服务器
- 建立TCP连接
- 发送HTTP请求
- 服务器处理请求
- 返回响应结果
- 关闭TCP连接
- 浏览器解析HTML
- 浏览器布局渲染
3、get和post方式
两者的区别
4、TCP和UDP的比较
TCP:
- 流量控制:使用滑动窗口
- 需要估计往返时间,进行超时判断
- 可靠数据传输:
- 超时之后,将超时间隔加倍
- 快速重传:连续收到3个冗余ACK,不用等到超时,直接进行重传
- 对于正确接收但是失序的报文段:不会被接收方确认,但是会被缓存起来,此时接收方响应的是一个累积的确认的最后一个正确接收的有序报文段。
- 拥塞控制:慢启动,快恢复
5、Socket了解么?
6、DNS
DNS:是一种能进行主机名到IP地址转换的目录服务。这就是域名系统(domain name system , DNS)的主要任务。
定义:
- 一个由分层的DNS服务器实现的分布式数据库
- 一个使得主机能够查询分布式数据库的应用层协议。
DNS服务器通常是运行BIND软件的UNIX机器。DNS协议运行在UDP之上,使用53端口。
DNS的解析过程:
DNS的解析是按照分级的解析策略。按照上图,首先查找本地的DNS服务器,如果没有,则开始向上依次请求:根服务器---> 顶级域名服务器 ----> 权威域名服务器 -----> 本地DNS服务器。
因为经过的步骤比较多,所以在DNS的设计过程中,大量使用了DNS缓存。DNS缓存的原理:在一个请求链中,当某个DNS服务器接受一个DNS回答时,他能够将映射在本地存储器中。但并不是永久的。
详细过程:
- 同一台用户主机上UN行者DNS应用的客户端。
- 浏览器从URL中抽取出主机名,例如:www.someschool.edu,并将这台主机名传给DNS应用的客户端
- 首先查找内存里面的DNS Cache , 然后查找本地磁盘里面的host文件
- DNS客户端向DNS服务器发送一个包含主机名的请求
- DNS客户最终会收到一份回答报文,其中含有对应于该主机名的IP地址。
- 一旦浏览器接收到来自DNS的该IP地址,他能够向位于该IP地址80端口的HTTP服务器进程发起一个TCP连接。
7、一次TCP请求之后,TCP连接会断开么?
一次结束之后,会断开
二面(2020-9-15)
1、红黑树插入过程
见百度一面面经
2、String底层的数据实现
底层使用数组实现
3、LinkedHashMap的底层数据实现
hashmap,对entry进行了修改,加了一个before和next键值对,分别指向前一个和后一个entry,保证按照插入顺序进行遍历
4、Redis底层定时任务的设计细节
- 定时删除:在设置键的过期时间的同时,创建一个定时器 timer). 让定时器在键的过期时间来临时,立即执行对键的删除操作。
- 惰性删除:放任键过期不管,但是每次从键空间中获取键时,都检查取得的键是否过期,如果过期的话,就删除该键;如果没有过期,就返回该键。
5、线程切换有哪些开销
https://zhuanlan.zhihu.com/p/79772089
主要是上下文切换:
开销分成两种,一种是直接开销、一种是间接开销。
(1)直接开销
就是在切换时,cpu必须做的事情,包括:
- 切换页表全局目录
- 切换内核态堆栈
- 切换硬件上下文(进程恢复前,必须装入寄存器的数据统称为硬件上下文)
- ip(instruction pointer):指向当前执行指令的下一条指令
- bp(base pointer): 用于存放执行中的函数对应的栈帧的栈底地址
- sp(stack poinger): 用于存放执行中的函数对应的栈帧的栈顶地址
- cr3:页目录基址寄存器,保存页目录表的物理地址
- ......
- 刷新TLB
- 系统调度器的代码执行
(2)间接开销
主要指的是虽然切换到一个新进程后,由于各种缓存并不热,速度运行会慢一些。如果进程始终都在一个CPU上调度还好一些,如果跨CPU的话,之前热起来的TLB、L1、L2、L3因为运行的进程已经变了,所以以局部性原理cache起来的代码、数据也都没有用了,导致新进程穿透到内存的IO会变多。 其实我们上面的实验并没有很好地测量到这种情况,所以实际的上下文切换开销可能比3.5us要大。
6、Linux中进程内存开销前10的进程信息
7、Linux中,将数据切分abc字符串,并分行展示出来
8、Linux中不包含
abc字符串的行
9、Redis为什么这么快
- 纯内存操作
- 单线程
- 高效的数据结构
- 合理的数据编码
- 其他方面的优化
10、垃圾回收器有哪些
见一点资讯二面面经
11、mysql中的覆盖索引
作业帮一面面经
12、当前堆快照堆
13、MVCC是干嘛的,实现细节
多版本控制,可以用来保持数据一致性,并且使用在读已提交和可重复读两种隔离级别上。实现细节是,在每一行数据后面加两个隐藏列,然后对应于最后修改的事务的版本号,当前版本的事务号只能读取比当前版本号小的数据行。
14、Redis中有没有什么比较危险的命令
美团
一面(2020-9-6)
1、SQL性能优化
2、手撕代码
二面(2020-9-6)
1、着重问了kafka相关的问题
中国农业银行
一面
1、什么时候会触发GC?什么时候会触发FullGC?
有一种回收策略叫分代垃圾回收。
分代垃圾回收,顾名思义,是将jvm管理的堆,分为不同的部分进行gc策略以达到优化内存管理的效果。jvm将堆分为年轻代与老年代,年轻代中又分为eden区
与survivor区
。
jvm在给一个对象分配内存的时,会优先考虑将对象分配到eden区,如果是对象较大的情况下会直接将较大的对象放入老年代
,在eden区的对象,在minorGC后还存活会进入survivor区,在survivor区里存活时间较长的对象会进入老年代
里。
所以说一般说的垃圾回收有两种情况
,一种是发生在新生代的minorGC
,一种是发生在老年代的fullGC
。
而永久代
通常被称为方法区
,方法区主要用来存放运行时常量的
(1)MinorGC发生的时机
当jvm无法为新的对象
分配空间的时候就会发生Minor gc,所以分配对象的频率越高
,也就越容易发生Minor gc。
(2)Full GC发生的时机
- System.gc()的调用:此方法的调用是建议JVM进行Full GC,虽然只是建议而非一定
- 老年代空间不足:老年代空间只有在新生代对象转入及创建大对象、大数组时才会出现不足的现象,当执行Full GC后空间仍然不足,则抛出oom
-
永久代空间不足:存放的为一些
class的信息、常量、静态变量
等数据,当系统中要加载的类、反射的类和调用的方法较多时,Permanet Generation可能会被占满,然后触发FullGC - HandlePromotionFaliture:在发生Minor GC之前,虚拟机会先检查老年代最大可用的连续空间是否大于新生代所有对象总空间,如果这个条件成立,那么Minor GC可以确保是安全的。如果不成立,则虚拟机会查看HandlePromotionFailure设置值是否允许担保失败。如果允许,那么会继续检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,如果大于,将尝试着进行一次Minor GC,尽管这次Minor GC是有风险的;如果小于,或者HandlePromotionFailure设置不允许冒险,那这时也要改为进行一次Full GC。
-
堆中分配很大的对象:所谓大对象,是指需要大量连续内存空间的java对象,
例如很长的数组,此种对象会直接进入老年代,而老年代虽然有很大的剩余空间,但是无法找到足够大的连续空间来分配给当前对象
,此种情况就会触发JVM进行Full GC。
2、JVM发生oom之后,发生在哪个层面
主要发生在堆空间中的老年代内存不够的时候。
3、JVM从哪些方面避免发生oom,调整哪个参数,从代码层面如何调整?
(1)jvm方面
- 尽量做到让对象在Minor GC阶段被回收
- 让对象在新生代多存活一段时间
- 将内存空间设置大一点,具体参数使用如下: -Xmx Java Heap最大值,默认值为物理内存的1/4,最佳设值应该视物理内存大小及计算机内其他内存开销而定; -Xms Java Heap初始值,Server端JVM最好将-Xms和-Xmx设为相同值,开发测试机JVM可以保留默认值; -Xmn Java Heap Young区大小,不熟悉最好保留默认值; -Xss 每个线程的Stack大小,不熟悉最好保留默认值;
(2)代码层面
不要创建过大的对象及数组。
4、JVM内存结构
5、在项目中使用的是什么注解来完成统一异常处理
@ControllerAdvice(annotations = Controller.class)
@ExceptionHandler({Exception.class})
6、springBoot中主要有哪些注解,介绍一下。
7、使用Redis设置过期时间的时候,使用的是什么命令设置过期时间的。
setEx(过期时间)
小米
一面(2020-9-14)
1、java中的IO,NIO,BIO,AIO
https://github.com/Snailclimb/JavaGuide/blob/master/docs/java/BIO-NIO-AIO.md
- BIO:采用 BIO 通信模型 的服务端,通常由一个独立的 Acceptor 线程负责监听客户端的连接。我们一般通过在
while(true)
循环中服务端会调用accept()
方法等待接收客户端的连接的方式监听请求,请求一旦接收到一个连接请求,就可以建立通信套接字在这个通信套接字上进行读写操作,此时不能再接收其他客户端连接请求,只能等待同当前连接的客户端的操作执行完成, 不过可以通过多线程来支持多个客户端的连接。 - NIO:NIO中的N可以理解为Non-blocking,不单纯是New。它支持面向缓冲的,基于通道的I/O操作方法。 NIO提供了与传统BIO模型中的
Socket
和ServerSocket
相对应的SocketChannel
和ServerSocketChannel
两种不同的套接字通道实现,两种通道都支持阻塞和非阻塞两种模式。阻塞模式使用就像传统中的支持一样,比较简单,但是性能和可靠性都不好;非阻塞模式正好与之相反。对于低负载、低并发的应用程序,可以使用同步阻塞I/O来提升开发速率和更好的维护性;对于高负载、高并发的(网络)应用,应使用 NIO 的非阻塞模式来开发。 - AIO:AIO 也就是 NIO 2。在 Java 7 中引入了 NIO 的改进版 NIO 2,它是异步非阻塞的IO模型。异步 IO 是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。AIO 是异步IO的缩写,虽然 NIO 在网络操作中,提供了非阻塞的方法,但是 NIO 的 IO 行为还是同步的。对于 NIO 来说,我们的业务线程是在 IO 操作准备好时,得到通知,接着就由这个线程自行进行 IO 操作,IO操作本身是同步的。(除了 AIO 其他的 IO 类型都是同步的,这一点可以从底层IO线程模型解释)
二面(2020-9-16)
1、聊聊入职意向
2、建议
了解一下阿里,京东,小米的技术架构,然后提前学习这些技术架构,为以后做准备。
网易互娱
一面(2020-9-21)
1、进程间通信方式
共享内存、消息队列、管道、信号量、信号、套接字
2、final和finally之间的区别
https://juejin.im/post/6844903614998134797
- final修饰符(关键字)可用于修饰类、变量和方法,用于表示它修饰的类、方法和变量不可改变。 final 修饰变量时,表示该变量一旦获取了初始值就不可被改变,final既可以修饰成员变量(包括类变量和实例变量),也可以修饰局部变量、形参。final修饰的变量不可被改变,一旦获取了初始值,该final变量的值就不能被重新赋值。将变量或方法声明为final,可以保证他们在使用的过程中不被修改。被final修饰的类,就意味着不能再派生出新的子类,不能作为父类而被子类继承。因此一个类不能既被abstract声明,又被final声明。
- finally(关键字)是在异常处理时,try-catch-finally语句中使用,finally常用来处理一些后续的工作。 在执行过程中,只要存在finally块,最终都会被执行。try块中的内容是在无异常时执行到结束。catch块中的内容,是在try块内容发生catch所声明的异常时,跳转到catch块中执行;finally块则是无论异常是否发生,都会执行finally块的内容,所以在代码逻辑中有需要无论发生什么都必须执行的代码,就可以放在finally块中。
3、mysql中的wal
http://mysql.taobao.org/monthly/2018/07/01/
在计算机领域,WAL(Write-ahead logging,预写式日志)是数据库系统提供原子性和持久化的一系列技术。
在使用WAL的系统中,所有的修改都先被写入到日志中,然后再被应用到系统状态中
。通常包含redo和undo两部分信息。
为什么需要使用WAL,然后包含redo和undo信息呢?举个例子,如果一个系统直接将变更应用到系统状态中,那么在机器掉电重启之后系统需要知道操作是成功了,还是只有部分成功或者是失败了(为了恢复状态)。如果使用了WAL,那么在重启之后系统可以通过比较日志和系统状态来决定是继续完成操作还是撤销操作
。
4、mysql中的聚簇索引和非聚簇索引
见作业帮一面面经
5、String是安全的么
安全
6、volatile
- 可见性:底层在对变量进行写入的时候,增加了一个lock锁,修改完变量之后,使用总线通知其他线程的工作内存中的该变量值失效,需要从主内存中重新获取该值。
- 不保证原子性:每一次只能读取最新的值,但是假如说对一个long类型进行操作,long为64位,会被拆分为两次32位的操作来实现,此时仅操作一半时,另一个线程来读取,获得的是一个不完整的long类型的值。所以不保证原子性
- 禁止指令重排序:通过在被volatile修饰的变量操作前后添加内存屏障来保证禁止指令重排序。
7、system.gc()会发生GC么?和GC相关的过程
不一定会发生
GC过程见农行一面面经
8、TCP四次挥手过程
见作业帮一面面经
9、epoll函数
见拼多多二面面经
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 经典排序算法-快速排序
- Stata | 解决 graph 中 x 轴刻度重叠问题
- Docker 垃圾回收机制补充
- 5分钟学会经典排序算法-归并排序
- Python | 爬取农业农村部政策法规并绘制词云图
- 5分钟学会经典排序算法-希尔排序
- Stata | 爬取企业景气指数与企业家信心指数
- Stata | 发出提示音的几种方式
- docker垃圾回收机制
- 让运维更简单的7种定时任务实现方式
- Notes | Chrome 浏览器常用快捷键
- Python | 从 PDF 中提取文本内容
- Stata | 自动生成中南财大2019拟录取硕士研究生分析报告
- Stata | 聊聊数据排序的几种方式
- 在生产中应用广泛的排序算法