米哈游的一次面试

492 阅读7分钟

String StringBuilder StringBuffer 之间的区别

在单线程下面,使用 StringBuilder 即可, 在多线程下面,使用 StringBuffer 即可,

synchornized 直接会升级成为重量级锁码,重量级别锁怎么实现的

在多线程中,为了保证线程的执行安全,引入了锁的概念, synchornized 的核心是监视器对象,每个 Java 对象都有一个监视器对象,线程想要进入 synchornized 里面执行代码,那么首先需要获得监视器对象。线程进入 synchornized 代码块之前,首先获得的是监视器对象的偏向锁,再次来一个线程竞争的时候会升级成为轻量级锁,有更多的线程加入进来竞争的话,锁会升级成为重量级锁。重量级锁的实现说白了底层就是一个排队机制。获得锁的线程执行代码,当然在这个期间锁是可以重入的。没有获得锁的线程在监视器对象上面排队获取锁即可。只有通过了这种排队机制,使得程序之间正确的运行,保证了线程安全。

Java 中的异常体系

image.png

异常和 Error 是同级别的,Error 是更加严重的问题,一般就是 JVM 宕机,不能执行程序了,类似于 OOM 的问题,使得程序不能正确的执行。

Exception:这个也就是正宗的异常,分为受检异常和非受检异常; 受检异常:开发人员必须处理的异常,一般是 ClassNotFoundException, 非受检异常:运行时异常,程序的运行期间可能抛出的异常,比如数组索引数量超出数组大小、NP 异常;Null Point 异常;

进程之间的通信方式

为什么需要进程之间的通信?

因为在 JVM 中可能同时运行很多的进程或者线程, 当一个请求达到服务器的时候,可能需要 JVM 中运行的多个进程协同的处理这个请求, 这个时候正确的控制进程之间的正确协作,所以是需要通信方式的。

怎么理解通信方式?

这里的通信方式不是简单的进程之间的交换数据,而是包括了进程之间协调复杂任务的完成、协调进程之间共享资源的访问,协调进程之间的同步操作,不能把进程之间的通讯简单的理解成为交换数据。

管道

一个进程将数据放入到管道中,另外一个进程从管道中读取数据即可。

匿名管道用于亲缘关系进程之间的通信限制(一般是父子进程之间的通信),命名管道是没有这个限制的。

消息队列

多个线程将数据放到消息队列中,从消息队列中消耗数据。

共享内存

多个线程直接使用一块共享的内存,减少了数据在内核之间的拷贝,提高了效率。

信号量

保证在多个线程竞争的条件下面,只能有一个线程能够获取到资源并且使用资源。

用户态和内核态之间的区别?

用户态:用户态的状态下,CPU 只能执行部分指令集,没有办法直接访问硬件资源,权限是比较低的。 内核态:CPU 几乎可以执行所有的指令以及访问所有的硬件资源,权限是比较高的。

为什么将一个应用程序划分为内核态和用户态?

1、安全性 权限划分使得用户程序只是访问部分的数据实现了对于数据的保护。

2、稳定性 在用户态的应用程序出现问题的时候,不会影响到整个系统,避免了因为部分用户程序的崩溃导致了系统崩溃的风险。

3、隔离性 用户态和内核态使得操作系统的内核与应用程序之间有了明显的边界,有助于系统的模块化维护

怎么加索引比较好?

CREATE INDEX index_name ON table_name(column_name);

将 table_name 的 column_name 列加上一个叫做 index_name 名字的索引;

什么是联合索引?

就是将一个数据库表中的多个字段联合到一起作为一个索引,这个索引就是联合索引。

什么是最左匹配原则?

比如说创建了 a b c 三个列的联合索引, 那么在写 SQL 语句进行匹配的时候 a ,a b, a b c, 都是可以匹配到的,也就是创建了一个索引相当于创建了三个索引,减少了创建索引的内存空间的浪费。

MySQL 的四种隔离级别

读未提交:读取没有提交的数据;可能发生脏读、不可重复读、幻读; 读已提交:读取已经提交的数据;可能发生不可重复读、幻读; 可重复度:事务执行过程中看到的数据和刚开始读取的数据是一致的;可能发生幻读; 串行化读:所有的事务排队获取数据,处理数据;所有的脏读、不可重复读、幻读都不会发生,因为是排队执行的。

脏读

一个事务读取了其他事务没有提交的数据,读取到了脏数据

不可重复读

一个事务两次读取数据库,但是数据不一样

幻读

一个事务在第二次读取数据的时候,发现多了几个数据行,看起来就是幻觉一样

InnoDB 怎么解决幻读问题的

在 InnoDB 读取数据的时候,事务执行第一个 select 的时候(因为一个事务中可能存在多个 select ,所有的 select 都使用同一个快照读,当然会避免幻读现象的发生),就会生成一个 ReadView ,之后整合事务的执行期间都是在使用这个 ReadView ,所以说使用的 ReadView 是一样的,那么就避免了幻读现象的产生。

输入一个网址之后会发生什么?

网络的本质是传输数据,也就是用户请求数据,服务器处理请求,返回用户需要的数据这样的流程。

这个问题有两个核心的额问题: 1、我需要把这个数据发送到什么地方? 2、我发送什么数据? 发送到什么地方,计算机网络中一大堆的协议来保证,比如 DNS 域名解析,将方便人们记忆的网址转换为 ip 地址; 发送的数据是什么,在计算机网络中,当然是数据包。数据被一层层的封装成数据包,经过物理光纤或者网线进行传输即可, 数据包到达服务器之后,将数据包进行解析,得到数据,然后继续进行处理即可。

粘包的原因

上面提到了网络上的数据是按照包的形式在传递的。那么可能在发送包的时候,为了提升传输的效率,将几个包同时发送到服务端,如果没有一些特殊控制的话,那么服务器是没有办法辨别每个包之间的界限的,就像是提交了一个 100 页的报告,没有页码,很可能发生错误。

至于怎么解决: 两种思路: 在发送包的时候,每一个包的后面放一个特殊的字符,服务器收到包之后,发现这个特殊字符,就知道这是一个包。 或者就是限定包的长度,每个包的大小是一样的,服务器也就能容易知道包之间的关系

算法

手写 LRU