小米 Java服务端开发
岗位描述
岗位职责:
1.参与小米公司级别平台后端服务, 负责项目建设与支持;
2.工作踏实负责,能积极有效与工作中的公司内部和外部合作方沟通;
3.持续服务优化, 负责建设高并发,高可用系统;
4.能调研和解决最终用户的实际问题;
5.参与服务端基础组件研发,核心架构建设, 负责技术调研,技术方案实施与研发;。
岗位要求
1、两年及以上后台服务器开发经验(有大型服务开发经验者优先);
2、精通Java编程,具备丰富的编程经验,能够熟练应用restlet/mybatis/spring等主流开发框;
3、熟悉分布式系统的设计和应用,熟悉分布式锁、NoSQL、消息队列等机制;
4、技术基础扎实,精通操作系统原理、数据结构、算法、网络编程和多线程编程等技术;
5、具备优秀的逻辑思维能力,善于分析和解决问题 ,对解决挑战性问题充满热情;
6、善于学习新知识,动手能力强,并有强烈的进取心。
面试过程
问题1:算法题
问:
给定包含n个整数的数组A,找到数组中每一个元素A左侧离它最近且小于该元素的整数数组下标,如果不存在返回-1;
样例1:
输入:
0 1 2 3 4 5
输出:
-1 0 1 2 3 4
样例2:
输入:
5 4 3 2 1 0
输出:
-1 -1 -1 -1 -1 -1
样例3:
输入:
4 8 7 9 10 5 3
输出:
-1 0 0 2 3 0 -1
答: 先说了n方的暴力方法,但是面试官提示说有o(N)的方法,所以继续网上找了找,是一个题的改编版
找出数组中每个数右边第一个比它大的元素--时间复杂度o(n)单调栈解法)
import java.util.Stack;
public class Main {
public static int[] findMinLefttWithStack(int[] array) {
if(array == null) {
return array;
}
int size = array.length;
int[] result = new int[size];
Stack<Integer> stack = new Stack<>();
stack.push(size-1);
int index = size-2;
while(index > -1) {
if(!stack.isEmpty() && array[index] < array[stack.peek()]) {
result[stack.pop()] = index;
} else {
stack.push(index);
index--;
}
}
while(!stack.isEmpty()) {
result[stack.pop()] = -1;
}
return result;
}
public static void main(String[] args) {
int[] array ={4,8,7,9,10,5,3};
int [] result=findMaxRightWithStack(array);
for(int i=0;i<array.length;i++){
System.out.print(array[i]+ " ");
}
System.out.println( "");
for(int j=0;j<array.length;j++){
System.out.print(result[j]+ " ");
}
}
}
先问了什么时候毕业,然后自我介绍,说了实验室项目
问题2:编程语言基础
问:Go语言什么时候开始接触的
答:研究生进入实验室开始了解的,最近找工作看java多一点
问:Go语言的特性有深入了解过吗,和java有啥区别
答:了解过,Go语言最大的特点就是并发性好一点,但是实验室项目没怎么用到(此时面试官要强行插话切入到并发话题,被我夺过来话了,并发没深入看,聊不下去)。Go的方法只能是唯一命名,没有重载重写。java是纯面向对象的,有重载重写。
问:就是没有泛型
问:java经验有没有
答:java没有相关web开发经验
问:问了本科,问了专业,问了本科学习时间
答:balabala
问:我们部门用java,我们有项目也会用到一些Go,正在尝试,但是还没有用起来。Go的有些问题问下:go里面有个channel的东西
答:知道,没用过
问:了解defer的用法吗
答:呃...不知道,没听说过
问:defer这个词没听说过吗,很常见的
答:哪部分的?
问:一般就是先加把锁,然后defer,然后unlock一下
答:go语言的锁吗
问:对的呀,很常见
问:java里面的多线程,你了解的多吗。 java里面有个锁通道,synchroniza关键字,volatile关键字,锁的优化,简述下synchroniza的过程是一个什么样子的吗
答:synchroniza修饰方法,synchroniza修饰代码块,synchroniza修饰实例对象。
synchroniza修饰实例对象。就把对象锁住了
synchroniza修饰静态方法,就把类给锁住了
问:听说过偏向锁/轻量级锁,可重入锁这些概念吗
答:锁的种类,有公平锁/非公平锁,可重入锁,独享锁/共享锁,互斥锁/读写锁,乐观锁/悲观锁,分段锁,自旋锁
问:jvm对synchroniza底层做了一个优化,实现过程中会有一个锁通道的过程,想问的是锁通道的过程具体是一个什么样子的。
答:呃.....
问:公平锁/非公平锁是一个什么概念
答:公平锁是指多个线程按照申请锁的顺序来获取锁。非公平锁是指多个线程获取锁的顺序并不是按照申请锁的顺序
问:不是按照申请锁的顺序,是按照什么顺序获取
答:呃.........(随便说了一点)有可能后申请的线程比先申请的线程优先获取锁。有可能,会造成优先级反转或者饥饿现象。
问:比如说ReentrantLock,它的实现大概是一个什么样子的,原来是非公平的,怎么就公平了
答:呃....
问:可重入锁是一个什么概念
答:在同一个线程在外层方法获取锁的时候,在进入内层方法会自动获取锁
问:内部随便一个方法都可以吗,还是说有一个限制条件
答:e....不清楚
问:比如说我现在获取到了一把锁,然后里面开了一个线程,新开了一个线程,然后还想获取一把锁,但是子线程并没有释放它,那它可以吗
答:e...会等待
问:为什么要等待了
答:e.....
问:hashmap和treemap内部结构大致是什么样子,具体是一个什么样的数据结构
答:hashmap balabal 数据和链表 value长度》=8链表转红黑树
treemap 有序 balabal
问题3:操作系统
问:操作系统里面有个虚拟内存,解释一下,它的作用是什么,还有就是为什么会有虚拟内存这个东西
答:e.....
问:进程和线程的区别
答:进程里面有好多的线程,线程是操作系统进行调度的基本单位。一个程序至少有一个进程,一个进程至少有一个线程。
问:线程有哪几种状态,以及几种状态中的转换关系是什么
答:开始,可运行,阻塞,等待,定时等待,终止
问:什么情况会进行状态转换说一下
答:e...
- 开始(New) - 还没有调用
start()
方法的线程处于此状态。 - 可运行(Runnable) - 已经调用了
start()
方法的线程状态。此状态意味着,线程已经准备好了,一旦被线程调度器分配了 CPU 时间片,就可以运行线程。 - 阻塞(Blocked) - 阻塞状态。线程阻塞的线程状态等待监视器锁定。处于阻塞状态的线程正在等待监视器锁定,以便在调用
Object.wait()
之后输入同步块/方法或重新输入同步块/方法。 - 等待(Waiting) - 等待状态。一个线程处于等待状态,是由于执行了 3 个方法中的任意方法:
Object.wait()``Thread.join()``LockSupport.park()
- 定时等待(Timed waiting) - 等待指定时间的状态。一个线程处于定时等待状态,是由于执行了以下方法中的任意方法:
Thread.sleep(sleeptime)``Object.wait(timeout)``Thread.join(timeout)``LockSupport.parkNanos(timeout)``LockSupport.parkUntil(timeout)
- 终止(Terminated) - 线程
run()
方法执行结束,或者因异常退出了run()
方法,则该线程结束生命周期。死亡的线程不可再次复生。
问:操作系统里面有一个死锁的概念,死锁具体是由什么产生的,然后会有什么解决方法
答:多个线程互相等待对方释放锁。死锁是当线程进入无限期等待状态时发生的情况,因为所请求的锁被另一个线程持有,而另一个线程又等待第一个线程持有的另一个锁。
避免一个线程同时获取多个锁;避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源;尝试使用定时锁 lock.tryLock(timeout),避免锁一直不能释放;对于数据库锁,加锁和解锁必须在一个数据库连接中里,否则会出现解锁失败的情况。
问题4:数据库
问:关于数据库这块,你说到了mongodb,还用过其他的数据库吗
答:sql server
问:那索引类型都有哪些
答:聚集索引和非聚集索引,
问:那什么是聚集索引,什么是非聚集索引
答:聚集索引,数据按索引顺序存储,子结点存储真实的物理数据 。索引的叶节点就是数据节点
非聚集索引,叶节点仍然是索引节点,只不过有一个指针指向对应的数据块。
问:mysql里面有一个很重要的概念,叫做 jianxvsuo,听说过吗
答:呃....没听说
问题5:网络
问:简述一下TCP里面的三次握手,四次挥手
答:第一次握手 - 客户端向服务端发送带有 SYN 标志的数据包。第二次握手 - 服务端向客户端发送带有 SYN/ACK 标志的数据包。第三次握手 - 客户端向服务端发送带有带有 ACK 标志的数据包。
第一次挥手 - 客户端向服务端发送一个 FIN 包,用来关闭客户端到服务端的数据传送。第二次挥手 - 服务端收到这个 FIN 包,向客户端发送一个 ACK 包,确认序号为收到的序号加 1。和 SYN 一样,一个 FIN 将占用一个序号。第三次挥手 - 服务端关闭与客户端的连接,向客户端发送一个 FIN 包。第四次挥手 - 客户端向服务端发送 ACK 包,并将确认序号设置为收到序号加 1。
问:那如果四次挥手最后一个包没有收到,会出现什么情况
答:额.....
问;http常见的状态码你了解过吗
答:
- 200 - 请求成功
- 301 - 资源(网页等)被永久转移到其它 URL
- 404 - 请求的资源(网页等)不存在
- 500 - 内部服务器错误
1 | 信息,服务器收到请求,需要请求者继续执行操作 |
---|---|
2 | 成功,操作被成功接收并处理 |
3 | 重定向,需要进一步的操作以完成请求 |
4 | 客户端错误,请求包含语法错误或无法完成请求 |
5 | 服务器错误,服务器在处理请求的过程中发生了错误 |
问: 那302 是什么状态
答:e....
问:那http常见的方法有哪些
答:
方法 | 描述 |
---|---|
GET | 请求指定的页面信息,并返回实体主体。 |
HEAD | 类似于 get 请求,只不过返回的响应中没有具体的内容,用于获取报头 |
POST | 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST 请求可能会导致新的资源的建立和/或已有资源的修改。 |
PUT | 从客户端向服务器传送的数据取代指定的文档的内容。 |
DELETE | 请求服务器删除指定的页面。 |
CONNECT | HTTP/1.1 协议中预留给能够将连接改为管道方式的代理服务器。 |
OPTIONS | 允许客户端查看服务器的性能。 |
TRACE | 回显服务器收到的请求,主要用于测试或诊断。 |
以下为面试准备
流程猜测
- 自我简介
- 项目中遇到的最大的难题,怎么解决的
- 谈谈你对小米的认识
- java 和go的区别
- mysql 和mongodb的区别
- 设计一个秒杀系统
他山之石
数据结构与算法
你所知道的排序算法有哪些,哪些是基于比较的
- 基于比较的排序
- 堆排序
- 选择排序 插入排序 冒泡排序
时间复杂度和空间复杂 稳定性
快排的步骤,你认为最关键的一步是哪个,最差情况的时间复杂度
写快拍
再写个快排非递归
递归会出现什么问题
讲桶排序,桶排序为什么是稳定的,桶排序维持稳定是否需要额外空间
二叉树遍历
java二叉树遍历——深度优先(DFS)与广度优先(BFS) 递归版与非递归版
二叉树层级遍历 同时输入层数
你所知道的数据结构有哪些?
讲一下什么是B 树
讲一下红黑树,插入数据时怎么判断红黑树是否平衡
红黑树
一般是用平衡因子差值判断是否平衡并通过旋转来实现平衡,左右子树树高不超过1
输出一个数组中某元素出现的次数超过数组长度一半的元素,没有则输出null。
二叉搜索树的 two sum 问题
链表反转
算法:链表1->2->3>4反转为1>4>2>3。
二分查找
二叉树公共父节点
n个新字符串插入到一个源字符串的指定位置。比较简单,实现的时候和面试官讨论了一波算法复杂度问题
给一个数列,输出top k
javacore
基础
数组链表区别
数组
一、数组的特点 1.在内存中,数组是一块连续的区域 2.数组需要预留空间
在使用前需要提前申请所占内存的大小,这样不知道需要多大的空间,就预先申请可能会浪费内存空间,即数组空间利用率低 ps:数组的空间在编译阶段就需要进行确定,所以需要提前给出数组空间的大小(在运行阶段是不允许改变的)
3.在数组起始位置处,插入数据和删除数据效率低。
插入数据时,待插入位置的的元素和它后面的所有元素都需要向后搬移 删除数据时,待删除位置后面的所有元素都需要向前搬移
4.随机访问效率很高,时间复杂度可以达到O(1)
因为数组的内存是连续的,想要访问那个元素,直接从数组的首地址处向后偏移就可以访问到了
5.数组开辟的空间,在不够使用的时候需要扩容,扩容的话,就会涉及到需要把旧数组中的所有元素向新数组中搬移 6.数组的空间是从栈分配的
二、数组的优点 随机访问性强,查找速度快,时间复杂度为O(1)
三、数组的缺点 1.头插和头删的效率低,时间复杂度为O(N) 2.空间利用率不高 3.内存空间要求高,必须有足够的连续的内存空间 4.数组空间的大小固定,不能动态拓展
链表 一、链表的特点 1.在内存中,元素的空间可以在任意地方,空间是分散的,不需要连续 2.链表中的元素都会两个属性,一个是元素的值,另一个是指针,此指针标记了下一个元素的地址
每一个数据都会保存下一个数据的内存的地址,通过此地址可以找到下一个数据
3.查找数据时效率低,时间复杂度为O(N)
因为链表的空间是分散的,所以不具有随机访问性,如要需要访问某个位置的数据,需要从第一个数据开始找起,依次往后遍历,直到找到待查询的位置,故可能在查找某个元素时,时间复杂度达到O(N)
4.空间不需要提前指定大小,是动态申请的,根据需求动态的申请和删除内存空间,扩展方便,故空间的利用率较高 5.任意位置插入元素和删除元素效率较高,时间复杂度为O(1) 6.链表的空间是从堆中分配的
二、链表的优点 1.任意位置插入元素和删除元素的速度快,时间复杂度为O(1) 2.内存利用率高,不会浪费内存 3.链表的空间大小不固定,可以动态拓展
三、链表的缺点 随机访问效率低,时间复杂度为0(N)
对于想要快速访问数据,不经常有插入和删除元素的时候,选择数组
对于需要经常的插入和删除元素,而对访问元素时的效率没有很高要求的话,选择链表
StringBuild和StringBuffer的区别
接口和抽象类的区别
抽象类(abstract-class)与接口(interface)有什么异同
讲解继承与组合的区别
谈谈volatile关键字
重载和重写的区别
const的用法,const多态原理
容器
HashSet 的底层实现
聊JAVA的集合set,set怎安实现允许重复的
hashMap底层实现
stl 中set map底层实现,与hashtable的差异,使用情况。
多线程
多线程,线程池,四中线程池。
java中怎么创建 一个线程
如何实现java多线程
- 继承Thread类,重写run()方法
- 实现Runnable 接口,并实现该接口的run()方法
run()方法和start()方法的区别
start()
和 run()
有什么区别?可以直接调用 Thread
类的 run()
方法么?
线程怎么同步?
多线程同步的实现方法有哪些
synchronized关键字
在Java语言中,每个对象都有一个对象锁与之相关联,该锁表明对象在任何时候只允许被一个线程所拥有,当一个线程调用对象的一段synchronized代码时,需要先获取这个锁,然后去执行相应的代码,执行结束后,释放锁。synchronized关键字有两种用法,synchronized方法和synchronized块。该关键字还可以作用于静态方法、类或某个实例。
1.1 synchronized方法,在方法的声明前加入synchronized关键字。
1.2 synchronized块,既可以把任意的代码段声明为synchronized,也可以指定上锁的对象,有非常的灵活性。
wait( ) 方法 与 notify( ) 方法
wait():使一个线程处于等待状态,并且释放所持有的对象的lock。
- sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉InterruptedException异常。
- notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。
Allnotity():唤醒所有处入等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让它们竞争。
Lock
JDK5新增加了Lock接口以及它的一个实现类ReentranLock,Lock也可以用来实现多线程的同步。
❶lock()。以阻塞的方式获取锁,如果获取到了锁,立即返回;如果别的线程持有锁,当前线程等待,直到获取锁后返回。
❷tryLock()。以非阻塞的方式获取锁。只是尝试性地去获取一下锁,如果获取到锁,立即返回true,否则,立即返回false。
❸tryLock(long timeout, TimeUnit unit)。如果获取了锁,立即返回,否则会等待参数给定的时间单元,在等待的过程中,如果获取了锁,就返回true,如果等待超时,返回false。
❹lockInterruptibly()。如果获取了锁,立即返回,如果没有获取锁,当前线程处于休眠状态,直到获得锁,或者当前线程被别的线程中断(会受到InterruptedException异常)。它与lock()方法最大的区别在于如果lock()方法获取不到锁,会一直处于阻塞状态,且会忽略interrupt()方法。
synchronized具体怎么用?能给什么对象上锁?
对象锁锁住的是,同样由synchronized修饰的方法或代码段。当然,这里排除了类锁。
Lock和synchronized的区别?它们都是可重入锁吗?哪个效率更高?
当需要以下高级特性时,才应该使用Lock:可定时的、可轮询的与可中断的锁获取操作,公平队列,或者非块结构的锁。否则,请使用synchronized。
锁有哪几种?可重入锁和不可重入锁的区别?
多线程中锁的种类
虚拟机
jvm了解吗?说一下你了解的jvm
说说JVM,内存区。
jvm启动的底层是怎么实现的
类装载机制了解吗?怎么实现的
输入输出io
javaweb
websocket在聊天室中的使用方式
Spring的 IOC原理
SpringMVC请求流程)
二面问了事务的实现原理(redo+undo),
MVCC,引擎之间的区别,
项目中用到了MapReduce,讲一下map和reduce的过程
数据库
谈谈对数据库索引的理解
从SQL优化角度谈谈索引
索引的数据结构,
b和b+的区别
左右连接
又问了数据库语句,第一个是查询分组计数,第二个是数据量大的时候使用limit分页,越往后查询越慢,怎么优化查询?
操作系统
进程间的通信方式
linux
Linux管道的作用
linux 常用指令介绍,chmod命令权限修改解释下
网络通信
(TCP该问的都问了)
三次握手,四次挥手
在浏览器中输入一个网址,浏览器的处理过程,涉及哪些层,用了哪些协议?
如果上面的是基于HTTPS的请求,会增加哪些流程呢(即HTTPS请求的流程)。HTTPS里面的对称加密的密钥是怎么发送的,能用RSA的私钥加密比它大的数据吗?
tcp的三次握手和四次挥手,
TCP滑动窗口
协程?(没听说过)
慢开始和拥塞控制原理,