2024年高频Java八股文面试题

1.什么是Spring?

Spring是个轻量级的框架,通过IOC达到松耦合的目的,通过AOP可以分离应用业务逻辑和系统服务进行内聚性的开发,不过配置各种组件时比较繁琐,所以后面才出选了SpringBoot的框架。 

2.IOC是什么?

IOC是控制反转,是一种思想,把对象的创建和调用从程序员手中交由IOC容器管理,降低对象之间的依赖关系。

创建一个bean的方式有xml方式、@Bean注解方式、@Componte方式

我们在对一个bean进行实例化后,要对他的属性进行填充,大多数我们都是使用 @Autowire直接的填充依赖注入的,他是有限按照类型进行匹配。

3.AOP是什么? 

AOP是面向切面编程,可以将那些与业务不相关但是很多业务都要调用的代码抽取出来,思想就是不侵入原有代码的情况下对功能进行增强。

SpringAOP是基于动态代理实现的,动态代理是有两种,一种是jdk动态代理,一种是cglib动态代理;

jdk动态代理是原理是利用反射来实现的,需要调用反射包下的Proxy类的newProxyInstance方法来返回代理对象,这个方法中有三个参数,分别是用于加载代理类的类加载器,被代理类实现的接口的class数组和一个用于增强方法的InvocaHandler实现类。

cglib动态代理原理是利用asm开源包来实现的,是把被代理类的class文件加载进来,通过修改它的字节码生成子类来处理

jdk动态代理要求被代理类必须有实现的接口,生成的动态代理类会和代理类实现同样的接口,cglib则,生成的动态代理类会继承被代理类。Spring默认使用jdk动态代理,当被代理的类没有接口时就使用cglib动态代理

篇幅限制下面就只能给大家展示小册部分内容了,这边整理了一份核心面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 面试专题

 需要全套面试笔记的【点击此处即可】免费获取

4.如何定义一个全局异常处理类?

想要定义一个全局异常处理类的话,我们需要在这个类上添加@ContaollerAdvice注解,然后定义一些用于捕捉不同异常类型的方法,在这些方法上添加@ExceptionHandler(value = 异常类型.class)和@ResponseBody注解,方法参数是HttpServletRequest和异常类型,然后将异常消息进行处理。

如果我们需要自定义异常的话,就写一个自定义异常类,该类需要继承一个异常接口,类属性包括final类型的连续id、错误码、错误信息,再根据需求写构造方法; 

5.如何使用aop自定义日志?

第一步:创建一个切面类,把它添加到ioc容器中并添加@Aspect注解

第二步: 在切面类中写一个通知方法,在方法上添加通知注解并通过切入点表达式来表示要对哪些方法进行日志打印,然后方法参数为JoinPoint

第三步:通过JoinPoint这个参数可以获取当前执行的方法名、方法参数等信息,这样就可以根据需求在方法进入或结束时打印日志

6.循环依赖是什么,怎么解决的?

循环依赖就是在创建 A 实例的时候里面包含着 B 属性实例,所以这个时候就需要去创建 B 实例,而创 建 B 实例过程中也包含着 A 实例。 这样 A 实例还在创建的过程当中,所以就导致 A 和 B 实例都创建不出来。

spring通过三级缓存来解决循环依赖:

一级缓存:单例池,缓存经过了已经初始化完毕的Bean

二级缓存 :半成品池,缓存还未初始化完毕的Bean

三级缓存:缓存的是获取Bean的代理对象的表达式

我们在创建 A 的过程中,先将 A 放入三级缓存 ,这时要创建B,B要创建A就直接去三级缓存中查找,并且判断需不需要进行 AOP 处理,如果需要就在三级缓存中获取A的代理对象,不需要就取A原始对象。然后将取出的对象放入二级缓存中,这个时候其他需要依赖 A 对象的直接从二级缓存中去获取即可。当B初始化完成进入一级缓存后,A 继续执行生命周期,当A完成了属性的注入后,就可以放入一级缓存了

spring2.6之前默认会解决循环依赖。在spring2.6之后需要通过配置开启解决循环依赖

7.Bean 的作用域

(1)Singleton:一个IOC容器只有一个

(2)Prototype:每次调用getBean()都会生成一个新的对象

(3)request:每个http请求都会创建一个自己的bean

(4)session:同一个session共享一个实例

(5)application:整个serverContext只有一个bean

(6)webSocket:一个websocket只有一个bean

8.Bean 生命周期

实例化 Instantiation->属性赋值 Populate->初始化 Initialization->销毁 Destruction
在这四步的基础上面,Spring 提供了一些拓展点:

*Bean 自身的方法: 包括了 Bean 本身调用的方法和通过配置文件中的 init-method 和 destroy-method 指定的方法
*Bean 级生命周期接口方法:包括了 BeanNameAware、BeanFactoryAware、InitializingBean 和 DiposableBean 这些接口的方法
*容器级生命周期接口方法:包括了 InstantiationAwareBeanPostProcessor 和 BeanPostProcessor 这两个接口实现,一般称它们的实现类为“后处理器”。
*工厂后处理器接口方法: 包括了 AspectJWeavingEnabler, ConfigurationClassPostProcessor, CustomAutowireConfigurer 等等非常有用的工厂后处理器接口的方法。工厂后处理器也是容器级的。在应用上下文装配配置文件之后立即调用。

9.Spring 事务原理?

spring事务有编程式和声明式,我们一般使用声明式,在某个方法上增加@Transactional注解,这个方法中的sql会统一成功或失败。

原理是:

当一个方法加上@Transactional注解,spring会基于这个类生成一个代理对象并将这个代理对象作为bean,当使用这个bean中的方法时,如果存在@Transactional注解,就会将事务自动提交设为false,然后执行方法,执行过程没有异常则提交,有异常则回滚、

10.spring事务失效场景

(1)事务方法所在的类没有加载到容器中

(2)事务方法不是public类型

(3)同一类中,一个没有添加事务的方法调用另外以一个添加事务的方法,事务不生效

(4)spring事务默认只回滚运行时异常,可以用rollbackfor属性设置

(5)业务自己捕获了异常,事务会认为程序正常秩序

11.spring事务的隔离级别

default:默认级别,使用数据库自定义的隔离级别

其它四种隔离级别与mysql一样

12.spring事务的传播行为

(1)支持当前事务,如果不存在,则新启一个事务

(2)支持当前事务,如果不存在,则抛出异常

(3)支持当前事务,如果不存在,则以非事务方式执行

(4)不支持当前事务,创建一个新事物

(5)不支持当前事务,如果已存在事务就抛异常

(6)不支持当前事务,始终以非事务方式执行

 篇幅限制下面就只能给大家展示小册部分内容了,这边整理了一份核心面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 面试专题

 需要全套面试笔记的【点击此处即可】免费获取

13.Spring IoC

20200904160557786.png

12.spring用了哪些设计模式

BeanFactory用了工厂模式,AOP用了动态代理模式,RestTemplate用来模板方法模式,SpringMVC中handlerAdaper用来适配器模式,Spring里的监听器用了观察者模式

14.SpringMV工作原理

SpringMVC工作过程围绕着前端控制器DispatchServerlet,几个重要组件有HandleMapping(处理器映射器)、HandleAdapter(处理器适配器)、ViewReslover(试图解析器)

工作流程:

(1)DispatchServerlet接收用户请求将请求发送给HandleMapping

 (2)HandleMapping根据请求url找到具体的handle和拦截器,返回给DispatchServerlet

(3)DispatchServerlet调用HandleAdapter,HandleAdapter执行具体的controller,并将controller返回的ModelAndView返回给DispatchServler

(4)DispatchServerlet将ModelAndView传给ViewReslover,ViewReslover解析后返回具体view

(5)DispatchServerlet根据view进行视图渲染,返回给用户

15.springboot自动配置原理

在spring—boot—autoconfigura包下存放了spring内置的自动配置类和spring.factories文件,这个文件中存放了这些配置类的全类名 ;

启动类@SpringbootApplication注解下,有三个关键注解

(1)@springbootConfiguration:表示启动类是一个自动配置类

(2)@CompontScan:扫描启动类所在包下及子包的组件到容器中

(3)@EnableConfigutarion,下面有个子注解@Import会导入上面所说的自动配置类,这些配置类会根据元注解的装配条件生效,生效的类就会被实例化,加载到ioc容器中;这些自动配置类还会通过xxxProperties文件里配置来进行属性设值

16 .springboot常用注解

@RestController                  :修饰类,该控制器会返回Json数据 

@RequestMapping("/path") :修饰类,该控制器的请求路径

@Autowired                         :  修饰属性,按照类型进行依赖注入

@PathVariable                     :  修饰参数,将路径值映射到参数上

@ResponseBody                 :修饰方法,该方法会返回Json数据

@RequestBody(需要使用Post提交方式) :修饰参数,将Json数据封装到对应参数中
@Controller@Service@Compont:  将类注册到ioc容器

@Transaction:开启事务

17.spring的bean是线程安全的吗?

spring的默认bean作用域是单例的,单例的bean不是线程安全的,但是开发中大部分的bean都是无状态的,不具备存储功能,比如controller、service、dao,他们不需要保证线程安全。

如果要保证线程安全,可以将bean的作用域改为prototype,比如像Model View。

另外还可以采用ThreadLocal来解决线程安全问题。ThreadLocal为每个线程保存一个副本变量,每个线程只操作自己的副本变量。

18.springcloud主要解决什么问题?

解决服务之间的通信、容灾、负载平衡、冗余问题,能方便服务集中管理,常用组件有注册中心、配置中心、远程调用。服务熔断、网关

19.CAP理论

C:一致性,这里指的强一致性,也就是数据更新完,访问任何节点看到的数据完全一致

A:可用性,就是任何没有发生故障的服务必须在规定时间内返回合正确结果

P:容灾性,当网络不稳定时节点之间无法通信,造成分区,这时要保证系统可以继续正常服务。提高容灾性的办法就是把数据分配到每一个节点当中,所以P是分布式系统必须实现的,然后需要在C和A中取舍

20.为什么不能同时保证一致性和可用性呢?

当网络发生故障时,如果要保障数据一致性,那么节点相互间就只能阻塞等待数据真正同步时再返回,就违背可用性了。如果要保证可用性,节点要在有限时间内将结果返回,无法等待其它节点的更新消息,此时返回的数据可能就不是最新数据,就违背了一致性了

21.熔断限流的理解? 

SprngCloud中用Hystrix组件来进行降级、熔断、限流

熔断是对于消费者来讲,当对提供者请求时间过久时为了不影响性能就对链接进行熔断,

限流是对于提供者来讲,为了防止某个消费者流量太大,导致其它更重要的消费者请求无法及时处理。限流可用通过拒绝服务、服务降级、消息队列延时处理、限流算法来实现

22.常用限流算法

计数器算法:使用redis的setnx和过期机制实现

漏桶算法:一般使用消息队列来实现,系统以恒定速度处理队列中的请求,当队列满的时候开始拒绝请求。

令牌桶算法:计数器算法和漏桶算法都无法解决突然的大并发,令牌桶算法是预先往桶中放入一定数量token,然后用恒定速度放入token直到桶满为止,所有请求都必须拿到token才能访问系统

六.Redis系列

1.redis为什么快?

(1)完全基于内存操作

(2)数据结构简单,对数据操作简单

(3)redis执行命令是单线程的,避免了上下文切换带来的性能问题,也不用考虑锁的问题

  (4) 采用了非阻塞的io多路复用机制,使用了单线程来处理并发的连接;内部采用的epoll+自己实现的事件分离器

其实Redis不是完全多线程的,在核心的网络模型中是多线程的用来处理并发连接,但是数据的操作都是单线程。Redis坚持单线程是因为Redis是的性能瓶颈是网络延迟而不是CPU,多线程对数据读取不会带来性能提升。

2.redis持久化机制

(1)快照持久化RDB

redis的默认持久化机制,通过父进程fork一个子进程,子进程将redis的数据快照写入一个临时文件,等待持久化完毕后替换上一次的rdb文件。整个过程主进程不进行任何的io操作。持久化策略可以通过save配置单位时间内执行多少次操作触发持久化。所以RDB的优点是保证redis性能最大化,恢复速度数据较快,缺点是可能会丢失两次持久化之间的数据

(2)追加持久化AOF

以日志形式记录每一次的写入和删除操作,策略有每秒同步、每次操作同步、不同步,优点是数据完整性高,缺点是运行效率低,恢复时间长

 篇幅限制下面就只能给大家展示小册部分内容了,这边整理了一份核心面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 面试专题

 需要全套面试笔记的【点击此处即可】免费获取

3.Redis如何实现key的过期删除?

采用的定期过期+惰性过期

定期删除 :Redis 每隔一段时间从设置过期时间的 key 集合中,随机抽取一些 key ,检查是否过期,如果已经过期做删除处理。
惰性删除 :Redis 在 key 被访问的时候检查 key 是否过期,如果过期则删除。

4.Redis数据类型应用场景

String:可以用来缓存json信息,可以用incr命令实现自增或自减的计数器

Hash:与String一样可以保存json信息

List:可以用来做消息队列,list的pop是原子性操作能一定程度保证线程安全

Set:可以做去重,比如一个用户只能参加一次活动 ;可以做交集求共友

SortSet :有序的。可以实现排行榜

5.Redis缓存穿透如何解决?

缓存穿透是指频繁请求客户端和缓存中都不存在的数据,缓存永远不生效,请求都到达了数据库。

解决方案:

(1)在接口上做基础校验,比如id<=0就拦截

(2)缓存空对象:找不到的数据也缓存起来,并设置过期时间,可能会造成短期不一致

(3)布隆过滤器:在客户端和缓存之间添加一个过滤器,拦截掉一定不存在的数据请求

6.Redis如何解决缓存击穿?

缓存击穿是值一个key非常热点,key在某一瞬间失效,导致大量请求到达数据库

解决方案:

(1)设置热点数据永不过期

(2)给缓存重建的业务加上互斥锁,缺点是性能低

7.Redis如何解决缓存雪崩?

缓存雪崩是值某一时间Key同时失效或redis宕机,导致大量请求到达数据库

解决方案:

(1)搭建集群保证高可用

(2)进行数据预热,给不同的key设置随机的过期时间

(3)给缓存业务添加限流降级,通过加锁或队列控制操作redis的线程数量

(4)给业务添加多级缓存

8.Redis分布式锁的实现原理

原理是使用setnx+setex命令来实现,但是会有一系列问题:

(1)任务时常超过缓存时间,锁自动释放。可以使用Redision看门狗解决

(2)加锁和释放锁的不是同一线程。可以在Value中存入uuid,删除时进行验证。但是要注意验证锁和删除锁也不是一个原子性操作,可以用lua脚本使之成为原子性操作

(3)不可重入。可以使用Redision解决(实现机制类似AQS,计数)

(4)redis集群下主节点宕机导致锁丢失。使用红锁解决

9.Redis集群方案

(1)主从模式:个master节点,多个slave节点,master节点宕机slave自动变成主节点

(2)哨兵模式:在主从集群基础上添加哨兵节点或哨兵集群,用于监控master节点健康状态,通过投票机制选择slave成为主节点

(3)分片集群:主从模式和哨兵模式解决了并发读的问题,但没有解决并发写的问题,因此有了分片集群。分片集群有多个master节点并且不同master保存不同的数据,master之间通过ping相互监测健康状态。客户端请求任意一个节点都会转发到正确节点,因为每个master都被映射到0-16384个插槽上,集群的key是根据key的hash值与插槽绑定

10.Redis集群主从同步原理

主从同步第一次是全量同步:slave第一次请求master节点会根据replid判断是否是第一次同步,是的话master会生成RDB发送给slave。

后续为增量同步:在发送RDB期间,会产生一个缓存区间记录发送RDB期间产生的新的命令,slave节点在加载完后,会持续读取缓存区间中的数据

11.Redis缓存一致性解决方案

Redis缓存一致性解决方案主要思考的是删除缓存和更新数据库的先后顺序

先删除缓存后更新数据库存在的问题是可能会数据不一致,一般使用延时双删来解决,即先删除缓存,再更新数据库,休眠X秒后再次淘汰缓存。第二次删除可能导致吞吐率降低,可以考虑进行异步删除。

先更新数据库后删除缓存存在的问题是会可能会更新失败,可以采用延时删除。但由于读比写快,发生这一情况概率较小。

但是无论哪种策略,都可能存在删除失败的问题,解决方案是用中间件canal订阅binlog日志提取需要删除的key,然后另写一段非业务代码去获取key并尝试删除,若删除失败就把删除失败的key发送到消息队列,然后进行删除重试。

12.Redis内存淘汰策略

当内存不足时按设定好的策略进行淘汰,策略有(1)淘汰最久没使用的(2)淘汰一段时间内最少使用的(3)淘汰快要过期的

七.计算机网络系列

1.TCP/IP模型20200904160558176.png
 2.浏览器输入地址后做了什么?

20200904160558322.png

 3.TCP三次握手

20200904160558436.png

4.为什么TCP不能两次握手

假设是两次握手,若客户端发起的连接请求阻塞在网络中,会造成该报文的重传,这时服务收到连接请求后会立刻进入连接状态,当双方传输完数据结束连接后,第一次阻塞的请求突然又到达了服务端,此时服务端又进入连接状态,而客户端不会响应服务端的连接确认报文

 篇幅限制下面就只能给大家展示小册部分内容了,这边整理了一份核心面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 面试专题

 需要全套面试笔记的【点击此处即可】免费获取

5.TCP四次挥手

20200904160558691.png

6.为什么要进入时间等待状态?

若客户端发送确认释放包后直接关闭,而服务端因为某种原因没有收到客户端的确认释放包,就会一直发送确认请求,而客户端永远不会再响应该请求。

7.TCP 滑动窗口

TCP 流量控制,主要使用滑动窗口协议,滑动窗口是接受数据端使用的窗口大小,用来告诉发送端接收端的缓存大小,以此可以控制发送端发送数据的大小,从而达到流量控制的目的。如果TCP发送方收到接收方的零窗口通知后,会启动持续计时器。计时器超时后向接收方发送零窗口探测报文,如果响应仍为0,就重新计时,不为0就打破死锁

8.TCP拥塞控制

发送方会维护一个拥塞窗口大小的状态变量,大小取决于网络的拥塞程度。发送方的发送窗口大小是取接收方接收窗口和拥塞窗口中较小的一个

拥塞控制有四种算法:

慢开始:从小到大主键发送窗口,每收到一个确认报文窗口大小指数增长

拥塞避免:当窗口大小到达一定阈值时,转为拥塞避免,每收到一个确认报文窗口大小+1。若此时网络超时,就把阈值调小一半,重新慢开始

快重传:要求接收方收到请求后要立即回复

快恢复:发送方连续收到多个确认时,就把拥塞避免阈值减小,然后直接开始拥塞避免

9.TCP超时重传

发送方在发送按数据后一定时间内没有收到接收方响应报文,就会重新发送刚刚的报文,接收到收到报文后会对该报文的序列号进行检验,已存在就抛弃

10.TCP可靠传输的实现

TCP是靠滑动窗口协议和连续ARQ协议配合流量控制和拥塞控制来保证的可靠传输。

ARQ是停止等待协议和自动重传请求,它规定TCP要为每一次传输的包编号,每发送一个包,要等待对方确认后才能发送下一个分组,若一段时间对方没有确认,就重新发送刚刚的报文。接收方会对数据包排序,把有序数据传给应用层,返回缺失的第一个ACK确认序列号给发送方,接收到收到报文后会对该报文的序列号进行检验,重复就丢弃。

流量控制是.....拥塞窗口上......(上面已经说了)

11.TCP报头有哪些信息

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MjczNjAyNA==,size_16,color_FFFFFF,t_70

 12.状态码

1xx:请求正在处理

2xx:请求成功处理

3xx:请求重定向   301:永久重定向      302:临时重定向       304:使用本地缓存

4xx:客户端错误   400:请求格式错误   403:没有访问权限    415:请求体过大

5xx:服务端错误

14.socket通信流程

(1)服务端创建socket并调用bind()方法绑定ip和端口号

(2)服务端调用listen()方法建立监听,此时服务的scoket还没有打开

(3)客户端创建socket并调用connect()方法像服务端请求连接

(4)服务端socket监听到客户端请求后,被动打开,调用accept()方法接收客户端连接请求,当accept()方法接收到客户端connect()方法返回的响应成功的信息后,连接成功

(5)客户端向socket写入请求信息,服务端读取信息

(6)客户端调用close()结束链接,服务端监听到释放连接请求后,也结束链接

八.linux系列

1.linux常用命令

ifconfig:查看网络接口详情

ping:查看与某主机是否能联通

ps -ef|grep 进程名称:查看进程号

lost -i 端口 :查看端口占用情况

top:查看系统负载情况,包括系统时间、系统所有进程状态、cpu情况

free:查看内存占用情况

kill:正常杀死进程,发出的信号可能会被阻塞

kill -9:强制杀死进程,发送的是exit命令,不会被阻塞

2.linux的io模型

IO是对磁盘或网络数据的读写,用户进程读取一次IO请求分为两个阶段:等待数据到达内核缓冲区和将内核缓冲区数据拷贝到用户空间,当用户去内核中拷贝数据时,要从用户态转为核心态

5中io模型:

(1)同步阻塞IO模型

用户进程发起io调用后会被阻塞,等待内核缓冲区数据准备完毕时就被唤醒,将内核数据复制到用户进程。这两个阶段都是阻塞的

(2)同步非阻塞IO模型

用户进程发起IO调用后,若内核缓冲区数据还未准备好,进程会继续干别的事,每隔一段时间就去看看内核数据是否准备好。不过将内核数据复制到用户进程这个阶段依旧是阻塞的

(3)IO多路复用模型

linux中把一切都看成文件,每个文件都有一个文件描述符(FD)来关联, IO多路复用模型就是复用单个进程同时监测多个文件描述符,当某个文件描述符可读或可写,就去通知用户进程。

(4)信号IO模型

用户进程发起IO调用后,会向内核注册一个信号处理函数然后继续干别的事,当内核数据准备就绪时就通知用户进程来进行拷贝。

(5)异步非阻塞模型

前面四种全是同步的。进程在发起IO调用后,会直接返回结果。待内核数据准备好时,由内核将数据复制给用户进程。两个阶段都是非阻塞的

 篇幅限制下面就只能给大家展示小册部分内容了,这边整理了一份核心面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 面试专题

 需要全套面试笔记的【点击此处即可】免费获取

4.IO多路复用详解

linux中把一切都看成文件,每个文件都有一个文件描述符(FD)来关联, IO多路复用模型就是复用单个进程同时监测多个文件描述符,当某个文件描述符可读或可写,就去通知用户进程。IO多路复用有三种方式

(1)select:采用数组结构,监测的fd有限,默认为1024;当有文件描述符就绪时,需要遍历整个FD数组来查看是哪个文件描述符就绪了,效率较低;每次调用select时都需要把整个文件描述符数组从用户态拷贝到内核态中来回拷贝,当fd很多时开销会很大;

(2)poll:采用链表结构,监测的文件描述符没有上限,其它的根select差不多

(3)epoll:采用红黑树结构,监测的fd没有上限,它有三个方法,epoll_create() 用于创建一个epoll实例,epoll实例中有一颗红黑树记录监测的fd,一个链表记录就绪的fd;epoll_ctl() 用于往epoll实例中增删要监测的文件描述符,并设置回调函数,当文件描述符就绪时触发回调函数将文件描述符添加到就绪链表当中;epoll_wait() 用于见擦汗就绪列表并返回就绪列表的长度,然后将就绪列表的拷贝到用户空间缓冲区中。

所以epoll的优点是当有文件描述符就绪时,只把已就绪的文件描述符写给用户空间,不需要每次都遍历FD集合;每个FD只有在调新增的时候和就绪的时候才会在用户空间和内核空间之间拷贝一次。

5.epoll的LT和ET模式

LT(默认):水平触发,当FD有数据可读的时候,那么每次 epoll_wait都会去通知用户来操作直到读完

ET:边缘触发,当FD有数据可读的时候,它只会通知用户一次,直到下次再有数据流入才会再通知,所以在ET模式下一定要把缓冲区的数据一次读完

九.场景题

 1.Java如何实现统计在线人数的功能?

博主写了另外一篇文章:http://t.csdn.cn/Q1S4h

2.电商网站可以分成哪些模块(或订单模块要完成哪些功能)?

用户模块(用户账户、会员等级、收货信息)、订单模块(订单编号、类型信息、状态信息、时间信息等)、商品模块(店铺信息、数量、价格等)、支付模块(支付方式、支付时间、支付单号等)、物流模块(物流公司、物流单号、物流状态等)

十.其他(RabitMQ、数据结构与算法、nginx、git、jwt登录等...)

1.RabbitMQ如何保证消息不丢失? 

发送端:

(1)创建一个消息状态表,开启RabbitMQ的confirm机制,当收到MQ回传的ACK以更新消息状态

(2)开启定时任务,隔断时间重新发送状态表中超时的任务,多次投递失败进行报警。

消费端:

(1)为了避免消息重复消费,要增加一张消息处理表,消费者拿到消息时判断消息处理表中当前消息是否已经存在,已经存在就抛弃,不存在就进行消费并放入记录表,消费和放入记录表要放在一个事务当中。

(2)开启手动ack模式,在消费者处理完业务后才返回ACK,避免消息还没有处理完就ACK。

 具体可以看博主另外一篇文章:(152条消息) RabbitMQ消息丢失的场景,如何保证消息不丢失?(详细讲解,一文看懂)_十八岁讨厌Java的博客-CSDN博客

2.RabbitMQ如何保证消费顺序

RabbitMQ消费顺序乱了是因为消费者集群拿到消息后对消息处理速度不同导致的,比如可能将增删改变成了增改删。

解决方法:为RabbitMQ创建多个Queue,每个消费者只监听其中一个Queue,同一类型的消息都放在一个queue中,同一个 queue 的消息是一定会保证有序的。

3.设计模式六大原则

(1)单一职责原则:一个类或者一个方法只负责一项职责,尽量做到类只有一个行为引起变化;
(2)里氏替换原则:子类可以扩展父类的功能,但不能改变原有父类的功能
(3)依赖倒置原则:高层模块不应该依赖底层模块,两者都应该依赖接口或抽象类
(4)接口隔离原则:建立单一接口,尽量细化接口
(5)迪米特原则:只关心其它对象能提供哪些方法,不关心过多内部细节
(6)开闭原则:对于拓展是开放,对于修改是封闭的

4.设计模式分类

创建型模式:主要是描述对象的创建,代表有单例、原型模式、工厂方法、抽象工厂、建造者模式

结构型模式:主要描述如何将类或对象按某种布局构成更大的结构,代表有代理、适配器、装饰

行为型模式:描述类或对象之间如何相互协作共同完成单个对象无法完成的任务,代表有模板方法模式、策略模式、观察者模式、备忘录模式

5.排序算法的时间复杂度

交换排序:冒泡排序(n^2,稳定),快速排序(nlogn,不稳定)
选择排序:直接选择排序(n^2,不稳定),堆排序(nlogn,不稳定s),
插入排序:直接插入排序(n^2,稳定),希尔排序(N^1.25,不稳定)
归并排序(nlogn,稳定)

6.大量数据排名,采用什么数据结构

当数据很大时,并且有序程度低时,堆排序最快;当数据很大时,并且有序程度高时,快速排序最快 

7.二叉树和堆之间联系或区别

堆是一种特殊的二叉树,所有父结点都比子结点要小的完全二叉树我们称为最小堆,所有父结点都比子结点要大,这样的完全二叉树称为最大堆。

8.平衡二叉树不平衡如何调整?

按照不平衡的情况有四种调整方法,分别是LR、RL、LL、RR调整

当不平衡的子树以当前节点为第一个节点往下再数到第三个节点的路径是先左再右时使用LR调整,LR是先将第二个节点旋转到第三个节点的左边,将第一个节点移动到第三个节点的右边;

RL与LR相反,RR是把第一个节点移到第三个节点左边,RR与LL相反

9.hash表冲突的解决方法

开放地址法:有线性探测法和平方探测法,当发生冲突时,继续往后找
再哈希法:构造多个哈希函数,发生冲突后使用下一个函数
链地址法:将hash值相同的记录用链表链接起来
建立公共溢出区:将哈希表分为基础表和益处表两部分,发生冲突的填入益处表

0.cookie和session的联系

因为http协议是无状态的,无法识别两次请求是否来自同一个客户端,于是就有了cookie和session的概念。

cookies:是存放在客户浏览器中,每次http请求都会携带,可以用来告知服务端两个请求是否来自同一浏览器,cookied的单个数据大小和存储个数是有限制的,不同浏览器限制不同,cookie的安全性较低。

session:当客户端第一次请求服务器时服务器为这个请求分配的一块区域,的存储结构为ConcurrentHashMap,服务器会将sessionId返回给客户端并存入cookie。相比cookie他的安全性更高,但失效时间较短

接下来客户端每次请求带着cookie,服务端会从中获取sessionId来进行匹配,用这套机制就实现了服务器和客户端进行有记忆的对话。

11.Nginx反向代理是什么,负载均衡算法有哪些?

反向代理是用来代理服务器接收请求的,然后将请求转发给内部网络的服务器,并将从服务器上得到的结果返回给客户端,此时代理服务器对外就表现为一个服务器。

负载均衡算法有:轮询(默认)、带权轮询、ip_hash(按ip哈希结果分配,能解决session共享问题)、url_hash(按访问的URL的哈希结果分配)、fair(根据服务端响应时间分配,响应时间短优先)

 篇幅限制下面就只能给大家展示小册部分内容了,这边整理了一份核心面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 面试专题

 需要全套面试笔记的【点击此处即可】免费获取

  • 15
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值