小米面试题
当然我还没面试过,这是牛客上面的真题。
1.HashMap
- 1.7之前是数组+链表,1.8是数组+链表+红黑树
- 1.7数组是Entry,采用的是头插法,在扩容时会改变链表中元素原本的顺序,以至于在并发场景下导致链表成环的问题。
- 1.8是Node,采用尾插入,在扩容时会保持链表元素原本的顺序,就不会出现链表成环的问题了。
- hashmap扩容机制:默认是16,当超过总容量的0.75f,也就是>12时会进行扩容,为什么是0.75呢?是因为满足统计学上的柏松分布,当扩容因子为0.75时达到最高的概率。每次扩容容量变为原来的两倍。
- 1.8后由于加入了红黑树,所以当数组某个位置的链表的节点>8时,同时数组的长度>=64时,链表转化为红黑树,如果数组长度<64,则仅仅进行数组扩容。如果链表减少到<5,红黑树就会退化为链表。
- 如果需要并发的hashmap可以使用currentHashMap
2.线程的状态
- 新建状态 NEW:尚未启动的线程状态
- 就绪状态 RUNNABLE:就绪状态,排队等待CPU分配资源
- 阻塞等待 BLOCKED :处于阻塞状态正在等待监视器锁,比如等待synchronized代码块
- 等待状态 WAITING : 某个线程调用了Object.wait(),等待其他线程调用Object.notify()
- 计时等待 TIMED_WAITING:比等待状态多个计时,如果超过等待时间就会进入此状态
- 终止状态 TERMINATED: 表示线程已经执行完成
3.栈和队列的区别
共同点:
- 都是线性结构
- 都是只能在线性表的端点插入和删除
- 都可以通过顺序结构和链表结构实现
- 插入和删除的时间复杂度都是O(1),空间复杂度也是一样
不同点:
- 队列先进先出,栈后进后出
4.事务和隔离级别
事务:
- 原子性:事务要不全部执行,要不就都不执行
- 一致性:当事务完成时,数据必须处于一致状态
- 隔离性:对数据进行修改的所有并发事务彼此是隔离的
- 持久性:事务完成后,对数据库的修改被永久保存
事务带来的四个问题:
- 丢失修改:事务A读取一个数据,同时事务B也读取这个数据,事务A修改提交,B也修改提交,把A修改的数据覆盖了。
- 脏读:事务A修改一个数据但还没提交,事务B读取这个数据,然后事务A运行报错,回滚了。事务B读取到的就是脏数据
- 不可重复读:事务A读取到一个数据,事务还没结束,事务B修改了这个数据,导致事务A再次读这个数据(也就是两次读数据之间)可能不一样。
- 幻读:事务A读取了几行数据,接着事务B插入了数据,在随后的查询中,事务A查询到原本不存在的一些数据。
隔离级别:
- Read-Uncommitted(读未提交):允许读取到还没提交的数据,会出现脏读、不可重复读、幻读。
- Read-Committed(读已提交):允许读取并发事务中已经提交的数据,会出现不可重复读、幻读。
- Repeatable-Read(可重复读):Mysql的InnoDb默认的隔离级别,对同一数据的多次读取都是一样的,会出现幻读。
- Serializable(串行化):最高隔离级别,完全符合ACID
5.乐观锁悲观锁
悲观锁:
- 每次拿数据都认为别人会去修改,所以每次拿数据的时候都会上锁,Java中的synchronized和ReentrantLock等独占锁就是悲观锁。
乐观锁:
- 每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和CAS算法实现。
6.线程和进程的区别
- 进程是资源分配的最小单位,线程是程序执行的最小单位
- 进程有自己的独立地址空间,每启动一个进程,系统都会为其分配地址空间,建立数据表来维护代码段、堆栈段和数据段,线程没有独立的地址空间,它使用相同的地址空间共享数据。
- CPU切换一个线程比进程花费小
- 创建一个线程比进程开销小
- 线程之间的通信更方便,同一个进程下,线程共享全局变量,静态变量等数据,进程之间的通信需要以通信的方式(IPC)进行
- 多线程程序更安全,一个进程死亡不会对另外一个进程造成影响(源于有独立的地址空间),多线程程序更不易维护,一个线程死亡,整个进程就死掉了(因为共享地址空间)
- 进程对资源保护要求大,开销大,效率相对较低,线程资源保护要求不高,开销小,效率高,可频繁切换
7.进程通信(五种)
进程间通信(IPC)
a.管道
通常是无名管道,是UNIX系统IPC最老形式
特点
- 它是半双工,具有固定的读端和写端
- 它只能用于具有亲缘关系的进程间的通信(也是父子进程或兄弟进程之间)
- 它可以看成是一种特殊文件,对于它的读写也可以使用普通的read、write等函数。只存在于内存中。
b.FIFO
FIFO,也称命名管道,是一种文件类型
特点
- FIFO可以在无关的进程之间交换数据,与无名通道不同
- FIFO有路径名与之相关联,它以一种特殊设备文件形式存在于文件系统中
c.消息队列
消息队列,是消息的链接表,存放在内核中。一个消息队列由一个标识符(即队列ID)来标识。
特点
- 消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先级。
- 消息队列独立于发生与接收进程。进程终止时,消息队列及其内容并不会被删除。
- 消息队列可以实现消息的随机查询,消息并不一定以先进先出的次序读取,也可以按消息的类型读取。
d.信号量
信号量(semaphore)与已经介绍过的IPC结构不同,它是一个计数器。信号量用于实现进程间的互斥与同步,而不是用于存储进程间通信数据。
特点
- 信号量用于进程间同步,若要在进程间传递数据需要结合共享内存
- 信号量基于操作系统的PV操作,程序对信号量的操作都是原子操作。
- 每次对信号量的PV操作不仅限于对信号量值加1或减1,而且可以加减任意正整数。
- 支持信号量组。
e.共享内存
共享内存(Shared Memory) ,指两个或多个进程共享一个给定的存储区。
特点
- 共享内存是最快的一种IPC,因为进程是直接对内存进行存取。
- 因为多个进程可以同时操作,所以需要进程同步。
- 信号量+共享内存通常结合在一起使用,信号量用来同步对内存的访问
8.启动线程的方式
- 继承Thread类,implements Runnable接口
- 实现Callable接口通过FutureTask包装器来创建Thread线程、使用ExecutorService、Callable、Future实现有返回结果的线程
9.gc算法,堆内存模型
gc算法有四种:复制算法,标记清除,标记整理,分代收集。
堆内存模型:私有(程序计数器、虚拟机栈、本地方法栈),公有(堆、方法区、运行时常量池)、直接内存
10.二叉树的遍历方式有几种,口述层序遍历
四种:前序、中序、后续、层序,如果使用递归遍历会比较消耗计算机资源,可以使用迭代
层序遍历一般会用队列、或者数组辅助遍历
11.快排,及其时间复杂度
时间复杂度:O(n log n)
计算机网络
1.tcp三次握手
2.状态码
1开头的状态码:(临时响应)表示临时响应并需要继续执行操作的状态代码。
- 100(继续)请求者应当继续提出请求。服务器返回此代码表示已收到请求的第一部分,正在等待其余部分。
- 101(切换协议)请求者已要求服务器切换协议,服务器已确认并准备切换
2开头的状态码:(成功)表示成功处理了请求的状态代码
- 200(成功)服务器已成功处理了请求,通常,这表示服务器提供了请求的网页
- 201(已创建)请求成功并且服务器创建了新的资源
3开头的状态码:(重定向)表示要完成请求,需要进一步操作。通常,这些状态代码用来重定向。
- 300 (多种选择) 针对请求,服务器可执行多种操作。 服务器可根据请求者 (user agent) 选择一项操作,或提供操作列表供请求者选择。
- 304 (未修改) 自从上次请求后,请求的网页未修改过。 服务器返回此响应时,不会返回网页内容。
4开头的状态码:(请求错误)表示请求可能出错,妨碍了服务器的处理
- 403(禁止)服务器拒绝请求
- 404(未找到)服务器找不到请求的网页
5开头状态码:(服务器错误)表示服务器在尝试处理请求时发生内部错误。
- 500(服务器内部错误)服务器遇到错误,无法处理请求
- 504 (网关超时) 服务器作为网关或代理,但是没有及时从上游服务器收到请求。
3.TCP,UDP的区别
- TCP面向连接(传递数据前先联系),UDP是无连接的,发送数据时不需要建立连接
- TCP提供可靠的服务,数据传输无差错,不丢失,且按序到达,UDP尽最大努力交付,即不保证可靠交付。
- UDP有较好的实时性,工作效率比TCP高,适用于广播通信
- TCP只能1对1,UDP可以1对1、1对多
- TCP对系统资源要求较多,UDP对系统资源要求较少
算法题
1.合并两个数组NC22
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
int last=m+n-1;
while(n){
if(m==0||nums1[m-1]<nums2[n-1]){
nums1[last--]=nums2[--n];
}else{
nums1[last--]=nums1[--m];
}
}
}