2023百度面试真题

2023-07-15 15:40:02 浏览数 (1)

【百度】面试真题:

1、SpingBoot 也有定时任务?是什么注解?

在 SpringBoot 中使用定时任务主要有两种不同的方式,一个就是使用 Spring 中的@Scheduled 注解,另一个则是使用第三方框架 Quartz。

使用 Spring 中的 @Scheduled 的方式主要通过 @Scheduled 注解来实现。

使用 Quartz ,则按照 Quartz 的方式,定义 Job 和 Trigger 即可。

2、请描述线程的生命周期,它们之间如何切换?

线程的生命周期包含 5 个阶段,包括:新建、就绪、运行、阻塞、销毁。

新建(NEW):就是刚使用 new 方法,new 出来的线程;

就绪(RUNNABLE):就是调用的线程的 start()方法后,这时候线程处于等待 CPU 分配资源阶段,谁先抢的 CPU 资源,谁开始执行;

运行(RUNNING):当就绪的线程被调度并获得 CPU 资源时,便进入运行状态,run方法定义了线程的操作和功能;

阻塞(BLOCKED):在运行状态的时候,可能因为某些原因导致运行状态的线程变成了阻塞状态,比如 sleep()、wait()之后线程就处于了阻塞状态,这个时候需要其他机制将处于阻塞状态的线程唤醒,比如调用 notify 或者 notifyAll()方法。唤醒的线程不会立刻执行 run 方法,它们要再次等待 CPU 分配资源进入运行状态;

Waiting(无限等待):一个线程在等待另一个线程执行一个(唤醒)动作时,该线程进入 Waiting 状态。进入这个状态后不能自动唤醒,必须等待另一个线程调用 notify 方法或者 notifyAll 方法时才能够被唤醒

销毁(TERMINATED):如果线程正常执行完毕后或线程被提前强制性的终止或出现异常导致结束,那么线程就要被销毁,释放资源;

3、什么情况线程会进入 WAITING 状态?

一个线程在等待另一个线程执行一个(唤醒)动作时,该线程进入 Waiting 状态。进入这个状态后不能自动唤醒,必须等待另一个线程调用 notify 方法或者 notifyAll 方法时才能够被唤醒。

调用 Object 对象的 wait 方法,但没有指定超时值。

调用 Thread 对象的 join 方法,但没有指定超时值。

调用 LockSupport 对象的 park 方法。

4、简述多进程开发中 join 和 deamon 的区别?

join:当子线程调用 join 时,主线程会被阻塞,当子线程结束后,主线程才能继续执行。

deamon:当子进程被设置为守护进程时,主进程结束,不管子进程是否执行完毕,都会随着主进程的结束而结束。

5、异步和同步、阻塞和非阻塞之间的区别?

同步

当一个 request 发送出去以后,会得到一个 response,这整个过程就是一个同步调用的过程。哪怕 response 为空,或者 response 的返回特别快,但是针对这一次请求而言就是一个同步的调用。

异步

当一个 request 发送出去以后,没有得到想要的 response,而是通过后面的 callback、状态或者通知的方式获得结果。可以这么理解,对于异步请求分两步:

调用方发送 request 没有返回对应的 response(可能是一个空的 response); 服务提供方将 response 处理完成以后通过 callback 的方式通知调用方。

对于 1)而言是同步操作(调用方请求服务方),对于 2)而言也是同步操作(服务方回掉调用方)。从请求的目的(调用方发送一个 request,希望获得对应的 response)来看,这两个步骤拆分开来没有任何意义,需要结合起来看,而这整个过程就是一次异步请求。异步请求有一个最典型的特点:需要 callback、状态或者通知的方式来告知调用方结果。

阻塞

阻塞调用是指调用方发出 request 的线程因为某种原因(如:等待系统资源)被服务方挂起,当服务方得到 response 后就唤醒挂起线程,并将 response 返回给调用方。

非阻塞

非阻塞调用是指调用方发出 request 的线程在没有等到结果时不会被挂起,并且直到得到response 后才返回。

阻塞和非阻塞最大的区别就是看调用方线程是否会被挂起。

6、为什么要分内核态和用户态?

假设没有这种内核态和用户态之分,程序随随便便就能访问硬件资源,比如说分配内存,程序能随意的读写所有的内存空间,如果程序员一不小心将不适当的内容写到了不该写的地方,就很可能导致系统崩溃。用户程序是不可信的,不管程序员是有意的还是无意的,都很容易将系统干到崩溃。

正因为如此,Intel 就发明了 ring0-ring3 这些访问控制级别来保护硬件资源,ring0 的就是我们所说的内核级别,要想使用硬件资源就必须获取相应的权限(设置 PSW 寄存器,这个操作只能由操作系统设置)。操作系统对内核级别的指令进行封装,统一管理硬件资源,然后向用户程序提供系统服务,用户程序进行系统调用后,操作系统执行一系列的检查验证,确保这次调用是安全的,再进行相应的资源访问操作。**内核态能有效保护硬件资源的安全。

7、说下类加载器与类加载?加载的类信息放在哪个区域?

一个类型从被加载到虚拟机内存开始,到卸载出内存为止,它的整个生命周期将会经历加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)和卸载(Unloading)七个阶段。其中验证、准备、解析三个部分统称为连接(Linking)。

Java 虚拟机设计团队把类加载阶段中“通过一个类的全限定名来获取描述该类的二进制流”这个动作放到 Java 虚拟机外部去实现。比便让程序应用自己决定如何取获取所需的类。实现这个动作的代码被称为“类加载器”(Class Loader)。

对于任意一个类,都必须由加载它的类加载器和这个类本身一起共同确立其在 Java 虚拟机中的唯一性,每一个类加载器,都拥有一个独立的类名称空间。

8、UDP 协议和 TCP 协议的区别?

TCP 基于连接,UDP 基于无连接

TCP 要求系统资源较多,UDP 较少

UDP 程序结构较简单

TCP 保证数据正确性,UDP 可能丢包

TCP 保证数据顺序,UDP 不保证

9、limit 1000000 加载很慢的话,你是怎么解决的呢?

方案一:如果 id 是连续的,可以这样,返回上次查询的最大记录(偏移量),再往下 limit select id,name from employee where id>1000000 limit 10.

方案二:在业务允许的情况下限制页数:

建议跟业务讨论,有没有必要查这么后的分页啦。因为绝大多数用户都不会往后翻太多页。

方案三:order by 索引(id 为索引)

select id,name from employee order by id limit 1000000,10

方案四:利用延迟关联或者子查询优化超多分页场景。(先快速定位需要获取的 id 段,然后再关联)

SELECT a.* FROM employee a, (select id from employee where 条件 LIMIT 1000000,10 ) b where a.id=b.id

10、MySQL 的索引分类是什么?

单列索引

普通索引:MySQL 中基本索引类型,没有什么限制,允许在定义索引的列中插入重复值和空值,纯粹为了查询数据更快一点。

唯一索引:索引列中的值必须是唯一的,但是允许为空值,l 主键索引:是一种特殊的唯一索引,不允许有空值。

组合索引:

多个字段组合上创建的索引,只有在查询条件中使用了这些字段的左边字段时,索引才会被使用,使用组合索引时遵循最左前缀集合。全文索引:

只有在 MyISAM 引擎上才能使用,只能在 CHAR,VARCHAR,TEXT 类型字段上使用全文索引,介绍了要求,说说什么是全文索引,就是在一堆文字中,通过其中的某个关键字等,就能找到该字段所属的记录行,比如有"你是个靓仔,靓女 ..." 通过靓仔,可能就可以找到该条记录

空间索引:

空间索引是对空间数据类型的字段建立的索引,MySQL 中的空间数据类型有四种,GEOMETRY、POINT、LINESTRING、POLYGON。在创建空间索引时,使用 SPATIAL 关键字。要求,引擎为 MyISAM,创建空间索引的列,必须将其声明为 NOT NULL。

11、什么是散列表? select * 和 select 1?

哈希表(Hash table,也叫散列表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。

有时候为了提高效率,只是为了测试下某个表中是否存在记录,就用 1 来代替。

12、MySQL 的主从复制了解吗?

主库将变更写入 binlog 日志,然后从库连接到主库之后,从库有一个 IO 线程,将主库的binlog 日志拷贝到自己本地,写入一个 relay 中继日志中接着从库中有一个 SQL 线程会从中继日志读取 binlog,然后执行 binlog 日志中的内容,也就是在自己本地再次执行一遍SQL。

13、Spring 框架事务注解用什么注解?使用该注解的失效场景?

@Transactional

Transactional 注解应用在非 public 修饰的方法上@Transactional 注解属性

propagation 设置错误

@Transactional 注解属性 rollbackFor 设置错误

同一个类中方法调用,导致@Transactional 失效

异常被 catch“吃了”导致@Transactional 失效

14、final、finally、finallize?finally 是在 return 之前执行还是之后?

finally 块里的代码一定会执行吗?

final 可以用来修饰类、方法、变量,分别有不同的意义,final 修饰的 class 代表不可以继承扩展,final 的变量是不可以修改的,而 final 的方法也是不可以重写的(override)。

finally 是 Java 保证重点代码一定要被执行的一种机制。可以使用 try-finally 或者 try-catch-finally 来进行类似关闭 JDBC 连接、保证 unlock 锁等动作。

finalize 是基础类 java.lang.Object 的一个方法,设计目的是保证对象在被垃圾收集前完成特定资源的回收。finalize 机制现在已经不推荐使用,并且在 JDK 9 开始被标记为deprecated。

finally 块的语句在 try 或 catch 中的 return 语句执行之后返回之前执行且 finally 里的修改语句可能影响也可能不影响 try 或 catch 中 return 已经确定的返回值,若 finally 里也有 return 语句则覆盖 try 或 catch 中的 return 语句直接返回。

finally 块里的代码不一定会执行。比如:

try 语句没有被执行到,如在 try 语句之前就返回了,这样 finally 语句就不会执行,这也说明了 finally 语句被执行的必要而非充分条件是:相应的 try 语句一定被执行到。

在 try 块中有 System.exit(0**

15、I/O 多路复用实现方式有哪些?

select

poll

epoll

16、select、poll、epoll 区别有哪些?

select:它仅仅知道了,有 I/O 事件发生了,却并不知道是哪那几个流(可能有一个,多个,甚至全部),我们只能无差别轮询所有流,找出能读出数据,或者写入数据的流,对他们进行操作。所以 select 具有 O(n)的无差别轮询复杂度,同时处理的流越多,无差别轮询时间就越长。

poll:poll 本质上和 select 没有区别,它将用户传入的数组拷贝到内核空间,然后查询每个fd 对应的设备状态, 但是它没有最大连接数的限制,原因是它是基于链表来存储的.epoll:epoll 可以理解为 event poll,不同于忙轮询和无差别轮询,epoll 会把哪个流发生了怎样的 I/O 事件通知我们。所以我们说 epoll 实际上是事件驱动(每个事件关联上 fd)的,此时我们对这些流的操作都是有意义的。(复杂度降低到了 O(1)),通过红黑树和双链表数据结构,并结合回调机制,造就了 epoll 的高效,epoll_create(),epoll_ctl()和epoll_wait()系统调用。

17、哈希算法解决哈希冲突方式有哪些?

解决哈希冲突的方法一般有:开放寻址法、链地址法(拉链法)、再哈希法、建立公共溢出区等方法。

18、如何保证 Redis 中的数据不丢失?

单机单节点模式

使用 AOF 和 RDB 结合的方式

RDB 做镜像全量持久化,AOF 做增量持久化。因为 RDB 会耗费较长时间,不够实时,在停机的时候会导致大量丢失数据,所以需要 AOF 来配合使用。

Redis 集群模式

master 节点持久化

如果采用了主从架构,那么建议必须开启 master node 的持久化!不建议用 slave node作为 master node 的数据热备,因为那样的话,如果你关掉 master 的持久化,可能在master 宕机重启的时候数据是空的,然后可能一经过复制,salve node 数据也丢了,master 就会将空的数据集同步到 slave 上去,所有 slave 的数据全部清空。

Redis 断点续传

从 redis 2.8 开始,就支持主从复制的断点续传,如果主从复制过程中,网络连接断掉了,那么可以接着上次复制的地方,继续复制下去,而不是从头开始复制一份。主备切换的过程,可能会导致数据丢失

解决异步复制和脑裂导致的数据丢失

redis.conf 中

min-slaves-to-write 1

min-slaves-max-lag 10

要求至少有 1 个 slave,数据复制和同步的延迟不能超过 10 秒

如果说一旦所有的 slave,数据复制和同步的延迟都超过了 10 秒钟,那么这个时候,master 就不会再接收任何请求了上面两个配置可以减少异步复制和脑裂导致的数据丢失。

19、如何保证 Redis 中的数据都是热点数据?

Redis 内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略。Redis 提供 6种数据淘汰策略:

volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的

数据淘汰 volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据

淘汰

volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据

淘汰

allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰

allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰

no-enviction(驱逐):禁止驱逐数据

20、Redis 持久化机制是如何做的?

RDB

RDB 持久化方式,是将 Redis 某一时刻的数据持久化到磁盘中,是一种快照式的持久化方法。

RDB 优点:

RDB 是一个非常紧凑(有压缩)的文件,它保存了某个时间点的数据,非常适用于数据的备份。

RDB 作为一个非常紧凑(有压缩)的文件,可以很方便传送到另一个远端数据中心 ,非常适用于灾难恢复.

RDB 在保存 RDB 文件时父进程唯一需要做的就是 fork 出一个子进程,接下来的工作全部由子进程来做,父进程不需要再做其他 IO 操作,所以 RDB 持久化方式可以最大化

redis 的性能.

与 AOF 相比,在恢复大的数据集的时候,RDB 方式会更快一些.

RDB 缺点:

Redis 意外宕机 时,会丢失部分数据 当 Redis 数据量比较大时,fork 的过程是非常耗时的,fork 子进程时是会阻塞的,在这期间 Redis 是不能响应客户端的请求的。

AOF

AOF 方式是将执行过的写指令记录下来,在数据恢复时按照从前到后的顺序再将指令都执行一遍。

AOF 优点:

使用 AOF 会让你的 Redis 更加持久化。

AOF 文件是一个只进行追加的日志文件,不需要在写入时读取文件。

Redis 可以在 AOF 文件体积变得过大时,自动地在后台对 AOF 进行重写 。

AOF 文件可读性高,分析容易。

AOF 缺点:l 对于相同的数据来说,AOF 文件大小通常要大于 RDB 文件 根据所使用的 fsync 策略,AOF 的速度可能会慢于 RDB混合持久化方式Redis 4.0 之后新增的方式,混合持久化是结合了 RDB 和 AOF 的优点,在写入的时候,先把当前的数据以 RDB 的形式写入文件的开头,再将后续的操作命令以 AOF 的格式存入文件,这样既能保证 Redis 重启时的速度,又能减低数据丢失的风险。

21、Redis 为什么在使用 RDB 进行快照时会通过子进程的方式进行实现?

通过 fork 创建的子进程能够获得和父进程完全相同的内存空间,父进程对内存的修改对于子进程是不可见的,两者不会相互影响;

通过 fork 创建子进程时不会立刻触发大量内存的拷贝,内存在被修改时会以页为单位进行拷贝,这也就避免了大量拷贝内存而带来的性能问题;

22、介绍下 MySQL 的主从复制原理?产生主从延迟的原因?

主从复制原理: 主库将变更写入 binlog 日志,然后从库连接到主库之后,从库有一个IO 线程,将主库的 binlog 日志拷贝到自己本地,写入一个 relay 中继日志中。 接着从库中有一个 SQL 线程会从中继日志读取 binlog,然后执行 binlog 日志中的内容,也就是在自己本地再次执行一遍 SQL。

主从延迟:

a. 主库的从库太多

b. 从库硬件配置比主库差

c. 慢 SQL 语句过多

d. 主从库之间的网络延迟

e. 主库读写压力大

23、父进程如果宕掉,子进程会怎样?

如果父进程是会话首进程,那么父进程退出后,子进程也会退出;反之如果父进程不是会话首进程,那么父进程退出后,子进程不会退出,而它的一个或多个子进程还在运行,那么这些子进程就成为孤儿进程。

24、孤儿进程和僵尸进程有什么区别?

孤儿进程:父进程结束了,而它的一个或多个子进程还在运行,那么这些子进程就成为孤儿进程(father died)。子进程的资源由 init 进程(进程号 PID = 1)回收。

僵尸进程:子进程退出了,但是父进程没有用 wait 或 waitpid 去获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中,这种进程称为僵死进程。

25、MySQL 中有哪几种锁?

表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。

行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。

页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。

26、互斥锁(mutex)和自旋锁(spinlock)分别在什么场景使用?

在多核机器中,如果锁住的“事务”很简单,占用很少的时间,就应该使用 spinlock,这个时候 spinlock 的代价比 mutex 会小很多。”事务”很快执行完毕,自旋的消耗远远小于陷入 sleep 和 wake 的消耗。如果锁住“事务”粒度较大,就应该使用 mutex,因为如果用spinlock,那么在“事务”执行过程中自旋很长时间还不如使得线程 sleep。

在单核机器中。spinlock 没有任何意义的,spinlock 只会浪费唯一核心的 cpu 时间片,这个时刻没有任何线程会运行的。所以单核机器中,不论锁住的”事务”的粒度大小都要使用。

27、描述 Synchronized、ReentrantLock 的区别 ?

synchronized 是关键字,ReentrantLock 是 API 接口

Lock 需要手动加锁,手动释放锁

synchronized 不可中断,ReentrantLock 可中断、可超时

synchronized 是非公平锁,ReentrantLock 公平、非公平皆可

ReentrantLock 支持 Condition,多条件

28、HashMap 扩容操作是怎么实现的?

在 jdk1.8 中,resize 方法是在 hashmap 中的键值对大于阀值时或者初始化时,就调用 resize 方法进行扩容;

每次扩展的时候,都是扩展 2 倍; 扩展后 Node 对象的位置要么在原位置,要么移动到原偏移量两倍的位置。

29、ConcurrentHashMap 1.7 与 1.8 区别?

1.8 采用 synchronized 代替可重入锁 ReentrantLock (现代 JDK 中,synchronized已经被不断优化,可以不再过分担心性能差异)

1.8 取消了 Segment 分段锁的数据结构,使用数组 链表 红黑树的结构代替 1.8 对每个数组元素加锁,1.7 对要操作的 Segment 数据段加锁

30、如何使用 Java 的反射?

通过一个全限类名创建一个对象Class.forName(“全限类名”); 例如:com.mysql.jdbc.Driver Driver 类已经被加载到 jvm中,并且完成了类的初始化工作就行了

类名.class; 获取 Class<?> clz 对象对象.getClass();

获取构造器对象,通过构造器 new 出一个对象Clazz.getConstructor([String.class]);

Con.newInstance([参数]);

通过 class 对象创建一个实例对象(就相当与 new 类名()无参构造器)Cls.newInstance();

通过 class 对象获得一个属性对象Field c=cls.getFields():获得某个类的所有的公共(public)的字段,包括父类中的字段。

Field c=cls.getDeclaredFields():获得某个类的所有声明的字段,即包括 public、private和 proteced,但是不包括父类的声明字段 通过 class 对象获得一个方法对象

Cls.getMethod(“方法名”,class……parameaType);(只能获取公共的)

Cls.getDeclareMethod(“方法名”);(获取任意修饰的方法,不能执行私有)

M.setAccessible(true);(让私有的方法可以执行)

让方法执行Method.invoke(obj 实例对象,obj 可变参数);-----(是有返回值的)

0 人点赞