lukaliou123 / lukaliou123.github.io

lukaliou123在2022年的面试用知识点总结
Other
5 stars 0 forks source link

百度Java后台面经知识点 #26

Open lukaliou123 opened 2 years ago

lukaliou123 commented 2 years ago

1.hashmap为什么用红黑树

红黑树相比avl树,在检索的时候效率其实差不多,都是通过平衡来二分查找。但对于插入删除等操作效率提高很多。红黑树不像avl树一样追求绝对的平衡,他允许局部很少的不完全平衡,这样对于效率影响不大,但省去了很多没有必要的调平衡操作,avl树调平衡有时候代价较大,所以效率不如红黑树,在现在很多地方都是底层都是红黑树的天下啦。 https://blog.csdn.net/m0_37609579/article/details/100904838

2.了解NIO吗

1.Java IO和NIO之间第一个最大的区别是,IO是面向流的,NIO是面向缓冲区的。 2.Java NIO的非阻塞模式,使一个线程从某通道发送请求读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取,而不是保持线程阻塞,所以直至数据变的可以读取之前,该线程可以继续做其他的事情。 3.Java NIO的选择器允许一个单独的线程来监视多个输入通道,你可以注册多个通道使用一个选择器,然后使用一个单独的线程来“选择”通道:这些通道里已经有可以处理的输入,或者选择已准备写入的通道。这种选择机制,使得一个单独的线程很容易来管理多个通道https://zhuanlan.zhihu.com/p/74129481

3.Java锁体系 syn lock 实现原理 应用参数

syn锁靠monitor喜加一 https://github.com/lukaliou123/lukaliou123.github.io/issues/7#issue-1149360515

4.创建线程的4个方法和线程池参数

thread callable runnable 匿名内部类 callable可以return

参数:7个,核心,最大,时间单位,存活时间,拒绝策略,阻塞队列,线程工厂 https://www.cnblogs.com/lifegoeson/p/13780720.html

5.Spring的三种属性注入方式

1.使用set方法进行注入 2.使用有参构造函数进行注入 3.使用p名称空间注入 https://segmentfault.com/a/1190000040849285

6.bean的生命周期

1.实例化 Instantiation 2.属性赋值 Populate 3.初始化 Initialization 4.销毁 Destruction https://segmentfault.com/a/1190000040365130 image https://juejin.cn/post/7075168883744718856

7.Redis为何快?单线程如何处理高并发

redis 是基于内存的,内存的读写速度非常快(纯内存); 数据存在内存中,数据结构用 HashMap,HashMap 的优势就是查找和操作的时间复杂度都是 O(1)

redis是单线程的,省去了很多上下文切换线程的时间(避免线程切换的资源消耗)。

redis 使用 I/O 多路复用技术,可以处理高并发的连接(非阻塞I/O)。(如果你懂 I/O 多路复用,可以展开讲一讲,展示你钻研的深度) cnblogs.com/darknebula/p/10072658.html

lukaliou123 commented 2 years ago

8.索引?b+树?脏读?

b+树,脏读 https://github.com/lukaliou123/lukaliou123.github.io/issues/9 索引: https://github.com/lukaliou123/lukaliou123.github.io/issues/20#issuecomment-1105397754

9.MVCC流程

1.获取事务自己事务ID,即trx_id。(这个也不是select的时候获取的,而是这个事务开启的时候获取的 也就是begin的时候) 2.获取ReadView(这个才是select的时候才会生成的) 3.数据库表中如果查询到数据,那就到ReadView中的事务版本号进行比较。 4.如果不符合ReadView的可见性规则, 即就需要Undo log中历史快照,直到返回符合规则的数据

MVCC是如何实现读已提交可重复读的呢? 其实其它流程都是一样的,读已提交和可重复读唯一的区别在于:在RC隔离级别下,是每个select都会创建最新的ReadView;而在RR隔离级别下,则是当事务中的第一个select请求才创建ReadView

看完下面这个例子你应该就明白了。 https://www.cnblogs.com/qdhxhz/p/15750866.html

10.如何高效的使用mysql表?如何设计

SQL语法优化和数据库结构优化(分库分表),以及别太多索引 https://github.com/lukaliou123/lukaliou123.github.io/issues/20

11.排查问题?如何查看是否走索引?具体命令、字段

使用explain看 https://www.cnblogs.com/acm-bingzi/p/mysqlExplain.html

12.sql

统计班级男女人数 https://blog.csdn.net/csulfy/article/details/54916402 统计班里不及格人数

13.算法

1.合并两个无序数组(归并排序) 2.字符串例如:“95823”,自由组合,求解比它大的中的最小组合。

3.回形填充n*n的数组 就是比如n=4,你要把二维数组填充成 10 11 12 1 9 16 13 2 8 15 14 3 7 6 5 4

  1. 排序取数组里最大的k个数 手写小根堆 5.一道二叉树的dfs(自己建树) 6.数组合并,求中位数 7.字符串匹配 8.算法leetcode 113 路径总和II 9.求二叉树左右子树最大深度差 10.走出迷宫的路径
lukaliou123 commented 2 years ago

14.有哪些线程安全的set

concurrent包下的CopyOnWriteArraySet 从源码可以看出,CopyOnWriteArraySet底层采用了CopyOnWriteArrayList数据结构来实现。在add元素时,采用的是可重入锁来实现线程安全。 https://jishuin.proginn.com/p/763bfbd64f94

15.voliate的作用

对于可见性,Java提供了volatile关键词来保证可见性和禁止指令重排 https://github.com/lukaliou123/lukaliou123.github.io/issues/7#issuecomment-1049949305

16 .synchronized能修饰哪些东西,它在修饰类和方法的时候有什么限制 类,方法,代码块 1.它无法中断一个正在等候获得锁的线程; 2.也无法通过投票得到锁,如果不想等下去,也就没法得到锁; 3.同步还要求锁的释放只能在与获得锁所在的堆栈帧相同的堆栈帧中进行,多数情况下,这没问题(而且与异常处理交互得很好),但是,确实存在一些非块结构的锁定更合适的情况

17.老生代里面都会有什么

老生代的空间通常都会非常大,里面存放的对象都是不太可能会被回收的。 会用CMS或G1

18.数据库创建索引的指令

在执行CREATE TABLE语句时可以创建索引,也可以单独用CREATE INDEXALTER TABLE来为表增加索引。 https://www.cnblogs.com/tianhuilove/archive/2011/09/05/2167795.html

19.Redis都用来做什么,用于什么场景

1、缓存 缓存现在几乎是所有中大型网站都在用的必杀技,合理的利用缓存不仅能够提升网站访问速度,还能大大降低数据库的压力。Redis提供了键过期功能,也提供了灵活的键淘汰策略,所以,现在Redis用在缓存的场合非常多。 2、排行榜 很多网站都有排行榜应用的,如京东的月度销量榜单、商品按时间的上新排行榜等。Redis提供的有序集合数据类构能实现各种复杂的排行榜应用。 3、计数器 什么是计数器,如电商网站商品的浏览量、视频网站视频的播放数等。为了保证数据实时效,每次浏览都得给+1,并发量高时如果19.Redis都用来做什么,用于什么场景每次都请求数据库操作无疑是种挑战和压力。Redis提供的incr命令来实现计数器功能,内存操作,性能非常好,非常适用于这些计数场景Redis Incr 命令将 key 中储存的数字值增一 4、分布式会话(不懂) 集群模式下,在应用不多的情况下一般使用容器自带的session复制功能就能满足,当应用增多相对复杂的系统中,一般都会搭建以Redis等内存数据库为中心的session服务,session不再由容器管理,而是由session服务及内存数据库管理。 5、分布式锁 在很多互联网公司中都使用了分布式技术,分布式技术带来的技术挑战是对同一个资源的并发访问,如全局ID、减库存、秒杀等场景,并发量不大的场景可以使用数据库的悲观锁、乐观锁来实现,但在并发量高的场合中,利用数据库锁来控制资源的并发访问是不太理想的,大大影响了数据库的性能。可以利用Redis的setnx功能来编写分布式的锁,如果设置返回1说明获取锁成功,否则获取锁失败,实际应用中要考虑的细节要更多。 6、 社交网络 点赞、踩、关注/被关注、共同好友等是社交网站的基本功能,社交网站的访问量通常来说比较大,而且传统的关系数据库类型不适合存储这种类型的数据,Redis提供的哈希、集合等数据结构能很方便的的实现这些功能。

20.redis实现分布式锁

1.Redis为单进程单线程模式,采用队列模式将并发访问变成串行访问,且多客户端对Redis的连接并不存在竞争关系Redis中可以使用setNx命令实现分布式锁。 2.当且仅当 key 不存在,将 key 的值设为 value。 若给定的 key 已经存在,则 setNx不做任何动作 3.SETNX 是『SET if Not eXists』(如果不存在,则 SET)的简写 4.返回值:设置成功,返回 1 。设置失败,返回 0 。 image .使用setNx完成同步锁的流程及事项如下: 6.使用SETNX命令获取锁,若返回0(key已存在,锁已存在)则获取失败,反之获取成功 7.为了防止获取锁后程序出现异常,导致其他线程/进程调用setNx命令总是返回0而进入死锁状态,需要为该key设置一个“合理”的过期时间释放锁,使用DEL命令将锁数据删除

21.实现分布式锁的三种方式

1.基于数据库实现分布式锁; 基于数据库的实现方式的核心思想是:在数据库中创建一个表,表中包含方法名等字段,并在方法名字段上创建唯一索引,想要执行某个方法,就使用这个方法名向表中插入数据,成功插入则获取锁,执行完成后删除对应的行数据释放锁。 2.基于缓存(Redis等)实现分布式锁; 3.基于Zookeeper实现分布式锁; ZooKeeper是一个为分布式应用提供一致性服务的开源组件,它内部是一个分层的文件系统目录树结构,规定同一个目录下只能有一个唯一文件名。基于ZooKeeper实现分布式锁的步骤如下:

(1)创建一个目录mylock; (2)线程A想获取锁就在mylock目录下创建临时顺序节点; (3)获取mylock目录下所有的子节点,然后获取比自己小的兄弟节点,如果不存在,则说明当前线程顺序号最小,获得锁; (4)线程B获取所有节点,判断自己不是最小节点,设置监听比自己次小的节点; (5)线程A处理完,删除自己的节点,线程B监听到变更事件,判断自己是不是最小的节点,如果是则获得锁

https://www.cnblogs.com/liuqingzheng/p/11080501.html

22.redis数据淘汰策略,最常用的是哪个

https://github.com/lukaliou123/lukaliou123.github.io/issues/10#issuecomment-1054204598

23 形成死锁的四个条件

(1) 互斥条件:一个资源每次只能被一个进程使用。 (2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。 (3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。 (4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系

24. 发送https请求之后的全套流程

https://github.com/lukaliou123/lukaliou123.github.io/issues/2#issuecomment-1047850672

25. 设计模式的六大原则

https://github.com/lukaliou123/lukaliou123.github.io/issues/12#issue-1156464384

lukaliou123 commented 2 years ago

26.缓存数据库一致性

https://segmentfault.com/a/1190000040130178 旁路缓存策略(Cache-Aside Strategy),其核心思想是:只有当有应用来请求时,才将对应的对象进行缓存。并且这种策略适用于读取频繁但是写入或更新不频繁的场景,即数据一旦写入后主要用于查询展示,基本不会更新。 删除策略,每次更新数据,删除对应缓存,再更新 1.延时双删方案 2.缓存删除重试

27.各种异常

https://github.com/lukaliou123/lukaliou123.github.io/issues/5

lukaliou123 commented 2 years ago

28.InnoDB为什么不用[红黑树而用B+树做索引

那么Mysql如何衡量查询效率呢?– 磁盘IO次数。 B-树/B+树 的特点就是每层节点数目非常多,层数很少,目的就是为了就少磁盘IO次数,但是B-树的每个节点都有data域(指针),这无疑增大了节点大小,说白了增加了磁盘IO次数(磁盘IO一次读出的数据量大小是固定的,单个数据变大,每次读出的就少,IO次数增多,一次IO多耗时),而B+树除了叶子节点其它节点并不存储数据,节点小,磁盘IO次数就少。这是优点之一。 另一个优点是: B+树所有的Data域在叶子节点,一般来说都会进行一个优化,就是将所有的叶子节点用指针串起来。这样遍历叶子节点就能获得全部数据,这样就能进行区间访问啦。在数据库中基于范围的查询是非常频繁的,而B树不支持这样的遍历操作。 B树是多路树,红黑树是二叉树!红黑树一个节点只能存出一个值,B树一个节点可以存储多个值,红黑树的深度会更大,定位时 红黑树的查找次数会大一些。

29.最左前缀原则,范围查询右侧字段失效

https://github.com/lukaliou123/lukaliou123.github.io/issues/15#issue-1164781703 https://github.com/lukaliou123/lukaliou123.github.io/issues/22#issuecomment-1110850169

lukaliou123 commented 2 years ago

29.运行时异常有什么

编译时异常与运行时异常的区别 运行时异常:都是RuntimeException类及其子类异常,如NullPointerException(空指针异常)、IndexOutOfBoundsException(下标越界异常)等,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。

30.Spring默认单例,那怎么变成多例的,就是怎么修改bean的作用域(使用@Scope)

默认singleton,改成prototype

31.项目要怎么使用AOP,整个流程说一下

https://segmentfault.com/a/1190000027084162

32.每一个controller里面都可以出现异常,怎么处理全部controller的异常

https://www.jianshu.com/p/d3fd250db622 SpringMVC为我们提供的Controller层异常处理真的是太方便了,尤其是@ExceptionHandler,推荐大家使用

33.AQS是什么

AbstractQueuedSynchronizer,抽象队列同步器,利用CAS实现

image image 内部有一个State变量,为整数,别的线程 就是并发包里的一个核心组件,里面有state变量、加锁线程变量等核心的东西,维护了加锁状态。 ReentrantLock这种东西只是一个外层的API,内核中的锁机制实现都是依赖AQS组件的。 线程进入,state变为1,可重入,可继续加,用完了,就减为0 别的线程过来看,用CAS,state是0才可进入

lukaliou123 commented 2 years ago

34.类被加载的六大时机

image https://blog.csdn.net/weixin_43167418/article/details/103145880

35.java内存不足的解决办法

1.linux上利用top命令查看所有进程,看看那些进程占用的内存太大了,选择性的kill,释放内存,但这个需要了解清楚,安歇进程是不需要的。 2.调整tomca中对jvm内存的配置,因为jvm主要内存就是指jvm堆内存。 https://www.superweb999.com/article/159418.html

36.Redis键值对有限制吗

最多容纳 2^32 个key

redis的key和string类型value限制均为512MB

String类型:一个String类型的value最大可以存储512M

List类型:list的元素个数最多为2^32-1个,也就是4294967295个。

Set类型:元素个数最多为2^32-1个,也就是4294967295个。

Hash类型:键值对个数最多为2^32-1个,也就是4294967295个。

Sorted set类型:跟Set类型相似。 https://blog.csdn.net/z69183787/article/details/103139464

lukaliou123 commented 2 years ago

37.软中断和硬中断

(1) 硬中断 由与系统相连的外设(比如网卡、硬盘)自动产生的。主要是用来通知操作系统系统外设状态的变化。比如当网卡收到数据包

的时候,就会发出一个中断。我们通常所说的中断指的是硬中断(hardirq)。

(2) 软中断 为了满足实时系统的要求,中断处理应该是越快越好。linux为了实现这个特点,当中断发生的时候,硬中断处理那些短时间

就可以完成的工作,而将那些处理事件比较长的工作,放到中断之后来完成,也就是软中断(softirq)来完成。

硬中断和软中断的区别

软中断是执行中断指令产生的,而硬中断是由外设引发的。

硬中断的中断号是由中断控制器提供的,软中断的中断号由指令直接指出,无需使用中断控制器

硬中断是可屏蔽的,软中断不可屏蔽。

硬中断处理程序要确保它能快速地完成任务,这样程序执行时才不会等待较长时间,称为上半部。

软中断处理硬中断未完成的工作,是一种推后执行的机制,属于下半部。

问:软中断所经过的操作流程是比硬中断的少吗?换句话说,对于软中断就是:进程 ->内核中的设备驱动程序;对于硬中断:硬件->CPU->内核中的设备驱动程序?

答:是的,软中断比硬中断少了一个硬件发送信号的步骤。产生软中断的进程一定是当前正在运行的进程,因此它们不会中断CPU。但是它们会中断调用代码的流程。

lukaliou123 commented 2 years ago

38.协程

协程,又称微线程,纤程。英文名Coroutine。 协程寄托在线程之上 协程刚好可以解决上述2个问题。协程运行在线程之上,当一个协程执行完成后,可以选择主动让出,让另一个协程运行在当前线程之上。协程并没有增加线程数量,只是在线程的基础之上通过分时复用的方式运行多个协程,而且协程的切换在用户态完成,切换的代价比线程从用户态到内核态的代价小很多。 优点:减少线程切换,而且写成切换在用户态,不会消耗CPU切换时间

39.用户态和内核态的切换

相信大家都听过这样的话「用户态和内核态切换的开销大」,但是它的开销大在那里呢?简单点来说有下面几点

1.保留用户态现场(上下文、寄存器、用户栈等) 2.复制用户态参数,用户栈切到内核栈,进入内核态 3.额外的检查(因为内核代码对用户不信任) 4.执行内核态代码 5.复制内核态代码执行结果,回到用户态 6.恢复用户态现场(上下文、寄存器、用户栈等) image

切换的几个场景

1.系统调用:用户态进程主动切换到内核态的方式,用户态进程通过系统调用向操作系统申请资源完成工作,例如 fork()就是一个创建新进程的系统调用,系统调用的机制核心使用了操作系统为用户特别开放的一个中断来实现,如Linux 的 int 80h 中断,也可以称为软中断

2.异常:当 C P U 在执行用户态的进程时,发生了一些没有预知的异常,这时当前运行进程会切换到处理此异常的内核相关进程中,也就是切换到了内核态,如缺页异常

3.中断:当 C P U 在执行用户态的进程时,外围设备完成用户请求的操作后,会向 C P U 发出相应的中断信号,这时 C P U 会暂停执行下一条即将要执行的指令,转到与中断信号对应的处理程序去执行,也就是切换到了内核态。如硬盘读写操作完成,系统会切换到硬盘读写的中断处理程序中执行后边的操作等 https://segmentfault.com/a/1190000039774784