嗨~我是可拟雀,一个后端开发工程师,毕业于某985大学,目前供职于bat某大厂核心部门后端。每天分享最新面经答案,希望在大环境不好的当下能帮到你,让你多积累面试经验。需要内推或者面经合集请评论哦。原文:八股集合,汗流浃背,但是确实学到了很多内容,是以前没有仔细看过的。目前记起来一些,后续想起来别的了再补充 操作系统Linux平常使用吗线程和进程的区别,还有什么类似进程和线程的吗什么是协程CPU满了怎么看,怎么办Linux下rm正在写入的文件会发生什么?那么该如何在不使用kill的情况下删除该文件磁盘满了怎么看进程状态以及特殊两种状态僵尸线程和孤儿线程是什么清空进程时什么进程还存活?网络tcp三次握手四次挥手为什么不能两次握手如何解决tcp包的粘连udp和tcp的区别udp如何变得安全Java基础hashmap的底层hashmap.get之后会发生什么什么时候链表转红黑树什么时候红黑树降级jmmJvm区域及作用老年代常用垃圾处理算法多线程threadlocal有没有使用threadlocal底层是什么(哈希表)threadlocal底层哈希表的key是什么数据库两种引擎区别事务的原理数据库的四大特性如何保证隔离性隔离级别分别有哪些MVCC有什么用什么是死锁。如何解决sql数据库如何解决死锁sql锁Spring基础springboot运行原理bean如何加载,循环依赖?aop底层了解什么设计模式代理模式在spring哪里使用过单例模式在spring哪里使用过包装者模式在spring哪里使用过接口类代理和非接口类代理的区别中间件redis基本类型Redis缓存穿透,击穿,雪崩及解决方法,bitmap项目相关常见限流算法答案概答:操作系统:线程和进程的主要区别体现在以下几个方面:基本单位:进程是系统进行资源分配和调用的独立单位,它拥有独立的地址空间和系统资源。而线程是进程内的一个执行单元,它是CPU调度和分派的基本单位,多个线程共享父进程的地址空间。数量与关系:一个进程至少包含一个线程,也可以包含多个线程。线程之间共享进程的资源,这使得线程间的通信更为方便和快捷。而进程之间则是相对独立的,需要通过显式机制如管道、消息队列等进行通信。执行方式:由于线程共享进程资源,线程之间的切换开销相对较小,因此多线程并发执行时效率更高。而进程间的切换则涉及更多资源分配和回收的操作,开销较大。除了进程和线程,协程是另一种轻量级的执行单元。协程不是进程或线程,其执行过程更类似于子例程或不带返回值的函数调用。协程的切换开销比线程更小,适用于高并发场景。当CPU满载时,可以通过系统监控工具如top、htop等查看CPU使用情况。若CPU使用率过高,可能需要优化程序算法、减少不必要的计算或增加CPU资源。在Linux下,如果尝试使用rm命令删除正在写入的文件,可能会导致数据丢失或损坏。因为rm命令会立即删除文件系统的引用,而正在写入的文件可能还有未写入磁盘的缓存数据。在不使用kill命令的情况下,可以尝试先停止写入进程(如通过发送信号或优雅地关闭程序),然后再删除文件。磁盘空间使用情况可以通过df -h命令查看。如果磁盘空间已满,需要及时清理不必要的文件或扩展磁盘容量。进程状态可以通过ps、top等命令查看。其中,僵尸线程是指子进程已经结束但父进程没有回收其资源,这可能导致资源浪费。而孤儿线程则是指父进程结束但子进程还在运行,这些子进程将被init进程(进程号为1)接管。在清空进程时,通常系统进程和服务进程(如init、sshd等)会存活下来,因为它们负责维护系统的基本功能和安全性。计算机网络:TCP三次握手和四次挥手的设计是基于网络通信的可靠性和安全性考虑的,不能简化为两次握手。TCP三次握手的主要目的是确认双方的发送和接收能力是否正常,以及初始化序列号,以保证后续数据传输的可靠性。在三次握手过程中,第一次握手由客户端发起SYN报文,第二次握手由服务端回应SYN+ACK报文,第三次握手由客户端回应ACK报文。这样的设计确保了双方都能发送和接收数据,并且初始化了序列号,为后续的数据传输做好了准备。而TCP四次挥手的主要目的是在数据传输结束后,双方能够安全、有序地释放连接资源。在四次挥手过程中,第一次挥手由客户端发起FIN报文,第二次挥手由服务端回应ACK报文,第三次握手由服务端发起FIN报文,第四次握手由客户端回应ACK报文。这样的设计确保了数据传输的完整性和连接释放的安全性。如果将TCP的握手和挥手过程简化为两次握手,可能会面临以下问题:无法确保双方的发送和接收能力都正常,可能导致数据传输失败或丢失。无法初始化序列号,使得后续的数据传输无法按序进行,导致数据混乱。无法安全、有序地释放连接资源,可能导致资源泄露或连接状态不一致。关于TCP包的粘连问题,一种常见的解决方案是采用定长发送的方式。也就是说,在发送数据时,将数据分包为固定长度的数据包进行发送。接收方在接收数据时,也按照固定的长度进行接收。这样,发送和接收就能一一对应,从而解决TCP包的粘连问题。但这种方法可能会引入一些额外的开销,比如在数据包长度不足固定长度时需要进行填充。UDP和TCP的主要区别体现在以下几个方面:连接性:UDP是无连接的协议,每个数据包都是独立的,发送端和接收端之间没有建立持久的连接。而TCP在数据传输前会建立一个可靠的连接,数据传输完成后再断开连接。可靠性:TCP提供可靠的数据传输,通过序号、确认和重传机制,确保数据按顺序、完整地传输到目的地。而UDP不提供可靠性保证,数据包可能会丢失或乱序。流量控制和拥塞控制:TCP支持流量控制和拥塞控制,以防止网络拥塞和数据丢失。而UDP不提供这些功能。要使UDP变得安全,可以考虑以下几种方法:实现多路径传输:通过利用多个网络路径同时进行文件传输,分散数据流量,避免单一路径的拥堵问题,提高UDP协议的传输速度和稳定性。应用数据重传机制:当接收端收到不完整的数据时,可以请求发送端重新发送丢失的数据段,保证数据的完整性和可用性。加入安全认证机制:通过使用加密算法和数字签名等技术,保证数据信息的机密性和完整性,防止黑客攻击和数据泄露。java基础1. HashMap的底层实现HashMap的底层实现主要依赖于数组和链表(在Java 8及以后版本中,当链表长度超过一定阈值后会转为红黑树),以及一个计算哈希值的函数。每个HashMap对象内部都有一个Node数组(Node<K,V>[] table),数组的每个元素是一个链表。当向HashMap中添加元素时,首先根据key的哈希值计算出其在数组中的索引位置,然后将该元素添加到对应索引位置的链表中。2. HashMap.get()之后会发生什么当调用HashMap的get()方法时,首先会根据key的哈希值计算出在数组中的索引位置,然后遍历该索引位置处的链表或红黑树,查找与给定key相等的元素。如果找到了,就返回对应的value;否则返回null。3. 什么时候链表转红黑树在Java 8及以后的版本中,当HashMap中的某个桶(bucket)的链表长度达到一定的阈值(TREEIFY_THRESHOLD,默认为8)时,链表会转换为红黑树。这样做的目的是为了优化性能,因为在链表较长时,查找元素的时间复杂度是O(n),而红黑树的查找时间复杂度为O(log n)。4. 什么时候红黑树降级当HashMap中的某个桶的红黑树节点数少于一定的阈值(UNTREEIFY_THRESHOLD,默认为6)时,红黑树会退化为链表。此外,在HashMap进行resize(扩容)时,即使桶中的节点数大于UNTREEIFY_THRESHOLD,也会将红黑树退化为链表,然后再重新计算索引位置并插入。5. JMM(Java内存模型)Java内存模型(Java Memory Model, JMM)定义了Java虚拟机(JVM)中多线程程序并发访问共享变量时的内存可见性、原子性和有序性问题。JMM通过Happens-Before规则来定义操作的可见性,确保多线程环境下的数据一致性。6. JVM区域及作用JVM(Java虚拟机)的内存区域主要包括以下几个部分:方法区:存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。堆:所有线程共享的一块内存区域,用于存放对象实例。根据对象的生命周期不同,堆内存可以细分为新生代和老年代。新生代又可以分为Eden区和两个Survivor区(S0和S1)。栈:每个线程都有一个私有的栈,用于存储局部变量和方法的执行过程。栈中的每个元素称为栈帧,每个方法执行时都会创建一个新的栈帧。程序计数器:一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器。字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令。本地方法栈:与Java栈类似,但它是为Native方法服务的。7. 老年代常用垃圾处理算法老年代中常用的垃圾处理算法主要有标记-清除和标记-整理两种。标记-清除:首先标记出所有需要回收的对象,然后统一回收所有被标记的对象。这种方法效率较高,但会产生内存碎片。标记-整理:首先标记出所有需要回收的对象,然后让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。这种方法不会产生内存碎片,但效率相对较低。JVM的垃圾回收算法并不局限于这两种,还有复制算法、分代收集算法等,它们会根据不同的使用场景进行优化和选择。多线程:ThreadLocal 的底层实现并不直接是一个哈希表(HashTable)。ThreadLocal 的实现涉及到了每个线程内部的 ThreadLocalMap。这个 ThreadLocalMap 是一个定制化的、用于存储线程局部变量的数据结构。每个 Thread 对象都持有一个 ThreadLocalMap 的引用,用于存储该线程特有的 ThreadLocal 变量。ThreadLocalMap 的内部实现,它确实使用了哈希表的概念,但并不是标准的 java.util.HashTable 或 java.util.HashMap。它是专门为 ThreadLocal 设计的,具有一些特定的优化和特性。在 ThreadLocalMap 中,key 是 ThreadLocal 的弱引用(WeakReference),而 value 是与之关联的线程局部变量值。弱引用的使用是为了允许 ThreadLocal 对象在不再被强引用时能够被垃圾回收,即使它的值(即 ThreadLocalMap 中的 entry)仍然存在。这是为了避免内存泄漏,因为线程可能会长时间存活,而 ThreadLocal 可能只在某个特定的代码块或任务中使用。ThreadLocal 底层并不是直接一个哈希表。ThreadLocalMap 内部使用了类似哈希表的结构来存储键值对。在这个“哈希表”中,key 是 ThreadLocal 的弱引用。虽然 ThreadLocalMap 的实现使用了哈希表的概念,但它并不是 java.util 包下提供的标准哈希表实现。它是专门为 ThreadLocal 的需求而定制的。数据库以下是关于两种引擎区别、事务的原理、数据库的四大特性、隔离性的保证、隔离级别、MVCC的作用、死锁的定义与解决,以及SQL数据库中的锁和死锁解决方案的详细解释:一、两种引擎区别通常这两种引擎指的是InnoDB和MyISAM,它们在许多方面存在差异:事务处理:InnoDB支持事务处理,而MyISAM不支持。事务是一种高级的处理方式,它确保了一组操作的原子性,即要么全部执行,要么全部不执行。外键支持:InnoDB支持外键,而MyISAM不支持。全文索引:MyISAM支持FULLTEXT类型的索引,而InnoDB不支持。行数统计:InnoDB不保存表的行数,需要扫描整个表来计算行数,而MyISAM可以简单地读出保存好的行数。自增长字段:在InnoDB中,自增长字段必须包含只有该字段的索引,而在MyISAM中,它可以和其他字段一起建立联合索引。二、事务的原理事务是并发控制的单位,是用户定义的一个操作序列。这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位。事务通常是以BEGIN TRANSACTION开始,以COMMIT或ROLLBACK结束。COMMIT表示提交,即将事务中所有对数据库的更新写回到磁盘上的物理数据库中去,事务正常结束。ROLLBACK表示回滚,即在事务运行的过程中发生了某种故障,系统将事务中对数据库的所有已完成的操作全部撤消,滚回到事务开始的状态。三、数据库的四大特性数据库的四大特性是ACID,即原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)。原子性:整个事务是不可分割的,要么全部执行,要么全部不执行。一致性:事务的执行结果要与业务的逻辑保持一致。隔离性:多个事务之间隔离开来,互不影响。持久性:一旦事务执行完毕,执行后的结果会永久的保存下来。四、如何保证隔离性数据库的隔离性主要通过锁机制和多版本并发控制(MVCC)技术来实现。锁机制可以防止多个事务同时修改同一数据,而MVCC则通过保存数据的多个版本来实现无锁或低锁的并发访问。五、隔离级别分别有哪些InnoDB支持的隔离级别有四种,从低到高分别为:读未提交、读已提交、可重复读和串行化。六、MVCC有什么用MVCC(Multiple Version Concurrency Control)的主要作用是解决读-写和写-写冲突,使得大多数读操作不用加锁,从而提高了并发性能。通过保存数据的多个版本来实现并发访问,避免了读操作之间的锁竞争。七、什么是死锁死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。八、如何解决死锁解决死锁的方法主要有以下几种:预防死锁:通过一次性分配所有资源、按序请求资源等方式来预防死锁的发生。避免死锁:通过银行家算法等来判断并避免系统进入不安全状态,从而避免死锁。检测与解除死锁:定期检测系统中是否发生死锁,一旦发生死锁,则采取解除死锁的措施。解除死锁通常涉及撤销一些进程,以便回收它们的资源,从而使得其他进程能够继续执行。九、sql数据库如何解决死锁在SQL数据库中,解决死锁的方法通常包括:设置合理的锁超时时间:当尝试获取锁超过设定的时间后,放弃锁请求,避免长时间等待导致死锁。优化事务设计:尽量减小事务的大小和持续时间,减少锁的持有时间,从而降低死锁的风险。避免在事务中执行用户输入:用户输入可能导致不可预测的行为,增加死锁的风险。使用低隔离级别:如果可能,使用较低的隔离级别,以减少锁的需求和冲突。定期监控和诊断:使用数据库提供的工具和日志来定期监控和诊断死锁情况,及时发现并解决潜在问题。十、sql锁SQL中的锁主要用于控制并发访问,保证数据的完整性和一致性。SQL锁主要分为共享锁和排他锁。共享锁允许多个事务同时读取同一资源,而排他锁则阻止其他事务对同一资源进行读取或修改。此外,根据锁定的粒度,还可以分为行级锁、页级锁和表级锁等。不同的数据库管理系统和存储引擎可能会有不同的锁实现和策略。spring相关Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架,它主要用于简化企业级应用的开发。Spring的核心功能包括IoC容器和AOP,它们分别用于管理对象之间的依赖关系和实现横切关注点(如日志、事务等)。Spring支持声明式事务管理,通过注解或XML配置即可轻松实现事务的控制。Spring还提供了丰富的数据访问支持,包括JDBC、Hibernate、MyBatis等集成。Spring Boot运行原理:Spring Boot的设计目的是简化Spring应用的初始搭建以及开发过程。它提供了大量的默认配置,使得开发者可以快速启动和运行Spring应用。Spring Boot的运行原理主要基于自动配置和起步依赖。自动配置会根据项目的类路径和依赖关系自动为应用提供默认的设置和功能;而起步依赖则是一组预定义的依赖关系,用于简化项目中所需库和框架的导入过程。Bean的加载与循环依赖:在Spring容器中,Bean的加载过程包括解析配置文件或注解、创建Bean实例、注入依赖等步骤。循环依赖是指两个或多个Bean相互依赖对方,形成一个闭环。Spring通过三级缓存机制来解决循环依赖问题。一级缓存存储成品对象,二级缓存存储半成品对象(已实例化但未完全初始化),三级缓存存储ObjectFactory用于解决代理对象的循环依赖。AOP底层实现:Spring AOP的底层实现主要基于动态代理技术。对于接口代理,Spring使用JDK动态代理;对于非接口类代理,Spring使用CGLIB库来实现。动态代理允许在运行时创建代理对象,并将横切关注点织入到目标对象的方法执行过程中。设计模式在Spring中的应用:单例模式:在Spring中,默认情况下Bean是单例的,即在整个Spring IoC容器中只创建一个Bean实例。工厂模式:Spring使用BeanFactory和ApplicationContext作为工厂来创建和管理Bean对象。代理模式:在Spring AOP中,代理模式被用于实现面向切面的编程。Spring通过动态代理为目标对象创建代理对象,并在代理对象上织入横切关注点。包装者模式(装饰器模式):在Spring中配置DataSource时,可能会使用到装饰器模式。当需要连接多个数据库时,可以根据需求切换不同的数据源。代理模式在Spring中的使用:在Spring AOP中,代理模式被广泛应用。Spring通过创建代理对象来增强目标对象的功能,实现横切关注点的织入。无论是JDK动态代理还是CGLIB代理,都是代理模式在Spring中的具体实现。接口类代理和非接口类代理的区别:接口类代理通常指的是JDK动态代理,它要求被代理的对象必须实现一个或多个接口。JDK动态代理通过反射机制在运行时创建接口的代理实例。非接口类代理则是指CGLIB代理,它不需要被代理的对象实现接口。CGLIB通过继承被代理的类来创建子类作为代理对象,因此可以代理没有实现接口的类。redis相关Redis是一个开源的使用ANSI C语言编写的、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。以下是关于Redis基本类型、缓存穿透、击穿、雪崩及解决方法和bitmap的详细解释:Redis基本类型:Redis支持五种基本数据类型,分别是:String:字符串类型,是Redis最基本的数据类型,可以存储任何类型的数据,包括字符串、数字和二进制数据等。List:列表类型,是一种有序的字符串列表,可以在头部或尾部添加元素。Set:集合类型,是一组无序、唯一的字符串集合,可以对集合进行并、交、差等集合运算。Hash:哈希类型,类似于Map的一种结构,key-value存储。Sorted Set:有序集合类型,与Set一样也是string类型元素的集合,且不允许重复的成员。不同的是每个元素都会关联一个double类型的分数。Redis正是通过分数来为集合中的元素进行从小到大的排序。Redis缓存穿透、击穿、雪崩及解决方法:缓存穿透:描述:客户端请求的数据在缓存和数据库中都不存在,导致缓存永远不会生效,请求都被打到数据库。解决方法:主动方案:增加id复杂度,避免被猜测到id规律;做好数据基础格式校验;加强用户权限校验;做好热点参数的限流。被动方案:缓存空对象,并为其设置一个TTL。但这种方法可能会有额外内存消耗,并可能造成短期的不一致。缓存击穿:描述:缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力。解决方法:设置热点数据永不过期;定时更新;使用互斥锁或布隆过滤器等方法。缓存雪崩:描述:缓存中数据大批量到过期时间,而查询数据量巨大,引起数据库压力过大甚至down机。和缓存击穿不同的是,缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。解决方法:保持缓存层的高可用;缓存不过期;优化缓存过期时间;使用互斥锁重建缓存等。Redis的Bitmap:Bitmap是一个通过最小的单位bit来进行0或1的设置,用来记录每一个元素对应的值或者状态。Redis的bitmap不是一种新的数据结构,而是基于String类型实现的位操作功能。Bitmap的常见应用场景包括日活统计、用户签到、统计独立用户数(UV)等。限流算法:常见的限流算法主要有以下几种:计数器算法:计数器算法是限流算法中最简单也最容易实现的一种。它通过对每个请求进行计数,当计数器的值超过设定的阈值时,触发限流策略。但这种算法存在临界问题,特别是在周期切换时,如果大量请求集中在周期末尾涌入,可能会导致限流失效。滑动窗口算法:滑动窗口算法是对计数器算法的一种改进,通过动态调整时间窗口来解决临界问题。它将时间划分为多个固定大小的窗口,并分别对每个窗口内的请求进行计数。当某个窗口内的请求数超过阈值时,触发限流策略。漏桶算法:漏桶算法基于时间的概念,将数据流想象成一个有固定容量的桶。当数据流进入桶时,如果桶未满,则数据被保留在桶中;如果桶已满,则新的数据会被丢弃或延迟处理。数据以一定的速率从桶中流出,从而控制整体的速率。令牌桶算法:令牌桶算法是另一种常见的限流算法,它通过模拟一个固定容量的桶和一定数量的令牌来实现。每个令牌代表一个请求的处理权限。请求到达时,如果桶中有令牌可用,则获取令牌并处理请求;否则,请求被拒绝或延迟处理。令牌以一定的速率添加到桶中,当桶满时,新的令牌会被丢弃。令牌漏斗算法:令牌漏斗算法结合了漏桶和令牌桶的概念。它将数据流想象成一个漏斗,每个时间间隔内漏斗会积累一定数量的令牌。请求到达时,需要获取令牌才能被处理。如果令牌不足,请求被拒绝或延迟。分布式令牌桶算法:在分布式环境中,多个服务器可能需要共享限流策略。分布式令牌桶算法允许多个服务器共同维护一个令牌桶,通过共享令牌来控制整个系统的流量。原文传送门
点赞 9
评论 0
全部评论

相关推荐

野猪不是猪🐗:现在的环境就是这样,供远大于求。 以前卡学历,现在最高学历不够卡了,还要卡第一学历。 还是不够筛,于是还要求得有实习、不能有gap等等... 可能这个岗位总共就一个hc,筛到最后还是有十几个人满足这些要求。他们都非常优秀,各方面都很棒。 那没办法了,看那个顺眼选哪个呗。 很残酷,也很现实
点赞 评论 收藏
分享
allin秋招的大菠萝很爱交友:后续,已拿offer ~查看图片
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务